b410844f816ebb57232e89f8dbc5fd484a9256a8
1 from abc
import ABCMeta
, abstractmethod
7 from collections
import OrderedDict
8 from collections
.abc
import Iterable
, MutableMapping
, MutableSet
, MutableSequence
12 from .._utils
import *
13 from .._unused
import *
17 "Shape", "signed", "unsigned",
18 "Value", "Const", "C", "AnyConst", "AnySeq", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
19 "Array", "ArrayProxy",
20 "Signal", "ClockSignal", "ResetSignal",
21 "UserValue", "ValueCastable",
22 "Sample", "Past", "Stable", "Rose", "Fell", "Initial",
23 "Statement", "Switch",
24 "Property", "Assign", "Assert", "Assume", "Cover",
25 "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "SignalSet",
30 """Deterministic Unique IDentifier."""
33 self
.duid
= DUID
.__next
_uid
38 """Bit width and signedness of a value.
40 A ``Shape`` can be constructed using:
41 * explicit bit width and signedness;
42 * aliases :func:`signed` and :func:`unsigned`;
43 * casting from a variety of objects.
45 A ``Shape`` can be cast from:
46 * an integer, where the integer specifies the bit width;
47 * a range, where the result is wide enough to represent any element of the range, and is
48 signed if any element of the range is signed;
49 * an :class:`Enum` with all integer members or :class:`IntEnum`, where the result is wide
50 enough to represent any member of the enumeration, and is signed if any member of
51 the enumeration is signed.
56 The number of bits in the representation, including the sign bit (if any).
58 If ``False``, the value is unsigned. If ``True``, the value is signed two's complement.
60 def __init__(self
, width
=1, signed
=False):
61 if not isinstance(width
, int) or width
< 0:
62 raise TypeError("Width must be a non-negative integer, not {!r}"
68 return iter((self
.width
, self
.signed
))
71 def cast(obj
, *, src_loc_at
=0):
72 if isinstance(obj
, Shape
):
74 if isinstance(obj
, int):
76 if isinstance(obj
, tuple):
78 warnings
.warn("instead of `{tuple}`, use `{constructor}({width})`"
79 .format(constructor
="signed" if signed
else "unsigned", width
=width
,
81 DeprecationWarning, stacklevel
=2 + src_loc_at
)
82 return Shape(width
, signed
)
83 if isinstance(obj
, range):
85 return Shape(0, obj
.start
< 0)
86 signed
= obj
.start
< 0 or (obj
.stop
- obj
.step
) < 0
87 width
= max(bits_for(obj
.start
, signed
),
88 bits_for(obj
.stop
- obj
.step
, signed
))
89 return Shape(width
, signed
)
90 if isinstance(obj
, type) and issubclass(obj
, Enum
):
91 min_value
= min(member
.value
for member
in obj
)
92 max_value
= max(member
.value
for member
in obj
)
93 if not isinstance(min_value
, int) or not isinstance(max_value
, int):
94 raise TypeError("Only enumerations with integer values can be used "
96 signed
= min_value
< 0 or max_value
< 0
97 width
= max(bits_for(min_value
, signed
), bits_for(max_value
, signed
))
98 return Shape(width
, signed
)
99 raise TypeError("Object {!r} cannot be used as value shape".format(obj
))
103 return "signed({})".format(self
.width
)
105 return "unsigned({})".format(self
.width
)
107 def __eq__(self
, other
):
108 if isinstance(other
, tuple) and len(other
) == 2:
109 width
, signed
= other
110 if isinstance(width
, int) and isinstance(signed
, bool):
111 return self
.width
== width
and self
.signed
== signed
113 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
116 if not isinstance(other
, Shape
):
117 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
120 return self
.width
== other
.width
and self
.signed
== other
.signed
124 """Shorthand for ``Shape(width, signed=False)``."""
125 return Shape(width
, signed
=False)
129 """Shorthand for ``Shape(width, signed=True)``."""
130 return Shape(width
, signed
=True)
133 class Value(metaclass
=ABCMeta
):
136 """Converts ``obj`` to an nMigen value.
138 Booleans and integers are wrapped into a :class:`Const`. Enumerations whose members are
139 all integers are converted to a :class:`Const` with a shape that fits every member.
141 if isinstance(obj
, Value
):
143 if isinstance(obj
, int):
145 if isinstance(obj
, Enum
):
146 return Const(obj
.value
, Shape
.cast(type(obj
)))
147 if isinstance(obj
, ValueCastable
):
148 return obj
.as_value()
149 raise TypeError("Object {!r} cannot be converted to an nMigen value".format(obj
))
151 def __init__(self
, *, src_loc_at
=0):
153 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
156 raise TypeError("Attempted to convert nMigen value to Python boolean")
158 def __invert__(self
):
159 return Operator("~", [self
])
161 return Operator("-", [self
])
163 def __add__(self
, other
):
164 return Operator("+", [self
, other
])
165 def __radd__(self
, other
):
166 return Operator("+", [other
, self
])
167 def __sub__(self
, other
):
168 return Operator("-", [self
, other
])
169 def __rsub__(self
, other
):
170 return Operator("-", [other
, self
])
172 def __mul__(self
, other
):
173 return Operator("*", [self
, other
])
174 def __rmul__(self
, other
):
175 return Operator("*", [other
, self
])
177 def __check_divisor(self
):
178 width
, signed
= self
.shape()
180 # Python's division semantics and Verilog's division semantics differ for negative
181 # divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
182 # completely by prohibiting such division operations.
183 raise NotImplementedError("Division by a signed value is not supported")
184 def __mod__(self
, other
):
185 other
= Value
.cast(other
)
186 other
.__check
_divisor
()
187 return Operator("%", [self
, other
])
188 def __rmod__(self
, other
):
189 self
.__check
_divisor
()
190 return Operator("%", [other
, self
])
191 def __floordiv__(self
, other
):
192 other
= Value
.cast(other
)
193 other
.__check
_divisor
()
194 return Operator("//", [self
, other
])
195 def __rfloordiv__(self
, other
):
196 self
.__check
_divisor
()
197 return Operator("//", [other
, self
])
199 def __check_shamt(self
):
200 width
, signed
= self
.shape()
202 # Neither Python nor HDLs implement shifts by negative values; prohibit any shifts
203 # by a signed value to make sure the shift amount can always be interpreted as
205 raise TypeError("Shift amount must be unsigned")
206 def __lshift__(self
, other
):
207 other
= Value
.cast(other
)
208 other
.__check
_shamt
()
209 return Operator("<<", [self
, other
])
210 def __rlshift__(self
, other
):
212 return Operator("<<", [other
, self
])
213 def __rshift__(self
, other
):
214 other
= Value
.cast(other
)
215 other
.__check
_shamt
()
216 return Operator(">>", [self
, other
])
217 def __rrshift__(self
, other
):
219 return Operator(">>", [other
, self
])
221 def __and__(self
, other
):
222 return Operator("&", [self
, other
])
223 def __rand__(self
, other
):
224 return Operator("&", [other
, self
])
225 def __xor__(self
, other
):
226 return Operator("^", [self
, other
])
227 def __rxor__(self
, other
):
228 return Operator("^", [other
, self
])
229 def __or__(self
, other
):
230 return Operator("|", [self
, other
])
231 def __ror__(self
, other
):
232 return Operator("|", [other
, self
])
234 def __eq__(self
, other
):
235 return Operator("==", [self
, other
])
236 def __ne__(self
, other
):
237 return Operator("!=", [self
, other
])
238 def __lt__(self
, other
):
239 return Operator("<", [self
, other
])
240 def __le__(self
, other
):
241 return Operator("<=", [self
, other
])
242 def __gt__(self
, other
):
243 return Operator(">", [self
, other
])
244 def __ge__(self
, other
):
245 return Operator(">=", [self
, other
])
248 width
, signed
= self
.shape()
250 return Mux(self
>= 0, self
, -self
)
255 return self
.shape().width
257 def __getitem__(self
, key
):
259 if isinstance(key
, int):
260 if key
not in range(-n
, n
):
261 raise IndexError(f
"Index {key} is out of bounds for a {n}-bit value")
264 return Slice(self
, key
, key
+ 1)
265 elif isinstance(key
, slice):
266 start
, stop
, step
= key
.indices(n
)
268 return Cat(self
[i
] for i
in range(start
, stop
, step
))
269 return Slice(self
, start
, stop
)
271 raise TypeError("Cannot index value with {}".format(repr(key
)))
273 def as_unsigned(self
):
274 """Conversion to unsigned.
279 This ``Value`` reinterpreted as a unsigned integer.
281 return Operator("u", [self
])
284 """Conversion to signed.
289 This ``Value`` reinterpreted as a signed integer.
291 return Operator("s", [self
])
294 """Conversion to boolean.
299 ``1`` if any bits are set, ``0`` otherwise.
301 return Operator("b", [self
])
304 """Check if any bits are ``1``.
309 ``1`` if any bits are set, ``0`` otherwise.
311 return Operator("r|", [self
])
314 """Check if all bits are ``1``.
319 ``1`` if all bits are set, ``0`` otherwise.
321 return Operator("r&", [self
])
324 """Compute pairwise exclusive-or of every bit.
329 ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set.
331 return Operator("r^", [self
])
333 def implies(premise
, conclusion
):
339 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
341 return ~premise | conclusion
343 def bit_select(self
, offset
, width
):
344 """Part-select with bit granularity.
346 Selects a constant width but variable offset part of a ``Value``, such that successive
347 parts overlap by all but 1 bit.
352 Index of first selected bit.
354 Number of selected bits.
359 Selected part of the ``Value``
361 offset
= Value
.cast(offset
)
362 if type(offset
) is Const
and isinstance(width
, int):
363 return self
[offset
.value
:offset
.value
+ width
]
364 return Part(self
, offset
, width
, stride
=1, src_loc_at
=1)
366 def word_select(self
, offset
, width
):
367 """Part-select with word granularity.
369 Selects a constant width but variable offset part of a ``Value``, such that successive
370 parts do not overlap.
375 Index of first selected word.
377 Number of selected bits.
382 Selected part of the ``Value``
384 offset
= Value
.cast(offset
)
385 if type(offset
) is Const
and isinstance(width
, int):
386 return self
[offset
.value
* width
:(offset
.value
+ 1) * width
]
387 return Part(self
, offset
, width
, stride
=width
, src_loc_at
=1)
389 def matches(self
, *patterns
):
392 Matches against a set of patterns, which may be integers or bit strings, recognizing
393 the same grammar as ``Case()``.
397 patterns : int or str
398 Patterns to match against.
403 ``1`` if any pattern matches the value, ``0`` otherwise.
406 for pattern
in patterns
:
407 if not isinstance(pattern
, (int, str, Enum
)):
408 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
411 if isinstance(pattern
, str) and any(bit
not in "01- \t" for bit
in pattern
):
412 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
413 "bits, and may include whitespace"
415 if (isinstance(pattern
, str) and
416 len("".join(pattern
.split())) != len(self
)):
417 raise SyntaxError("Match pattern '{}' must have the same width as match value "
419 .format(pattern
, len(self
)))
420 if isinstance(pattern
, int) and bits_for(pattern
) > len(self
):
421 warnings
.warn("Match pattern '{:b}' is wider than match value "
422 "(which has width {}); comparison will never be true"
423 .format(pattern
, len(self
)),
424 SyntaxWarning, stacklevel
=3)
426 if isinstance(pattern
, str):
427 pattern
= "".join(pattern
.split()) # remove whitespace
428 mask
= int(pattern
.replace("0", "1").replace("-", "0"), 2)
429 pattern
= int(pattern
.replace("-", "0"), 2)
430 matches
.append((self
& mask
) == pattern
)
431 elif isinstance(pattern
, int):
432 matches
.append(self
== pattern
)
433 elif isinstance(pattern
, Enum
):
434 matches
.append(self
== pattern
.value
)
439 elif len(matches
) == 1:
442 return Cat(*matches
).any()
444 def shift_left(self
, amount
):
445 """Shift left by constant amount.
455 If the amount is positive, the input shifted left. Otherwise, the input shifted right.
457 if not isinstance(amount
, int):
458 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
460 return self
.shift_right(-amount
)
461 if self
.shape().signed
:
462 return Cat(Const(0, amount
), self
).as_signed()
464 return Cat(Const(0, amount
), self
) # unsigned
466 def shift_right(self
, amount
):
467 """Shift right by constant amount.
477 If the amount is positive, the input shifted right. Otherwise, the input shifted left.
479 if not isinstance(amount
, int):
480 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
482 return self
.shift_left(-amount
)
483 if self
.shape().signed
:
484 return self
[amount
:].as_signed()
486 return self
[amount
:] # unsigned
488 def rotate_left(self
, amount
):
489 """Rotate left by constant amount.
499 If the amount is positive, the input rotated left. Otherwise, the input rotated right.
501 if not isinstance(amount
, int):
502 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
504 return Cat(self
[-amount
:], self
[:-amount
]) # meow :3
506 def rotate_right(self
, amount
):
507 """Rotate right by constant amount.
517 If the amount is positive, the input rotated right. Otherwise, the input rotated right.
519 if not isinstance(amount
, int):
520 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
522 return Cat(self
[amount
:], self
[:amount
])
530 Value to be assigned.
535 Assignment statement that can be used in combinatorial or synchronous context.
537 return Assign(self
, value
, src_loc_at
=1)
541 """Bit width and signedness of a value.
550 >>> Signal(8).shape()
551 Shape(width=8, signed=False)
552 >>> Const(0xaa).shape()
553 Shape(width=8, signed=False)
557 def _lhs_signals(self
):
558 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
561 def _rhs_signals(self
):
565 raise TypeError("Value {!r} cannot be evaluated as constant".format(self
))
572 """A constant, literal integer value.
577 shape : int or tuple or None
578 Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
579 in this constant and whether it is signed (can represent negative values).
580 ``shape`` defaults to the minimum possible width and signedness of ``value``.
590 def normalize(value
, shape
):
591 width
, signed
= shape
592 mask
= (1 << width
) - 1
594 if signed
and value
>> (width
- 1):
598 def __init__(self
, value
, shape
=None, *, src_loc_at
=0):
599 # We deliberately do not call Value.__init__ here.
600 self
.value
= int(value
)
602 shape
= Shape(bits_for(self
.value
), signed
=self
.value
< 0)
603 elif isinstance(shape
, int):
604 shape
= Shape(shape
, signed
=self
.value
< 0)
606 shape
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
607 self
.width
, self
.signed
= shape
608 self
.value
= self
.normalize(self
.value
, shape
)
611 return Shape(self
.width
, self
.signed
)
613 def _rhs_signals(self
):
620 return "(const {}'{}d{})".format(self
.width
, "s" if self
.signed
else "", self
.value
)
623 C
= Const
# shorthand
626 class AnyValue(Value
, DUID
):
627 def __init__(self
, shape
, *, src_loc_at
=0):
628 super().__init
__(src_loc_at
=src_loc_at
)
629 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
630 if not isinstance(self
.width
, int) or self
.width
< 0:
631 raise TypeError("Width must be a non-negative integer, not {!r}"
635 return Shape(self
.width
, self
.signed
)
637 def _rhs_signals(self
):
642 class AnyConst(AnyValue
):
644 return "(anyconst {}'{})".format(self
.width
, "s" if self
.signed
else "")
648 class AnySeq(AnyValue
):
650 return "(anyseq {}'{})".format(self
.width
, "s" if self
.signed
else "")
654 class Operator(Value
):
655 def __init__(self
, operator
, operands
, *, src_loc_at
=0):
656 super().__init
__(src_loc_at
=1 + src_loc_at
)
657 self
.operator
= operator
658 self
.operands
= [Value
.cast(op
) for op
in operands
]
661 def _bitwise_binary_shape(a_shape
, b_shape
):
662 a_bits
, a_sign
= a_shape
663 b_bits
, b_sign
= b_shape
664 if not a_sign
and not b_sign
:
665 # both operands unsigned
666 return Shape(max(a_bits
, b_bits
), False)
667 elif a_sign
and b_sign
:
668 # both operands signed
669 return Shape(max(a_bits
, b_bits
), True)
670 elif not a_sign
and b_sign
:
671 # first operand unsigned (add sign bit), second operand signed
672 return Shape(max(a_bits
+ 1, b_bits
), True)
674 # first signed, second operand unsigned (add sign bit)
675 return Shape(max(a_bits
, b_bits
+ 1), True)
677 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
678 if len(op_shapes
) == 1:
679 (a_width
, a_signed
), = op_shapes
680 if self
.operator
in ("+", "~"):
681 return Shape(a_width
, a_signed
)
682 if self
.operator
== "-":
683 return Shape(a_width
+ 1, True)
684 if self
.operator
in ("b", "r|", "r&", "r^"):
685 return Shape(1, False)
686 if self
.operator
== "u":
687 return Shape(a_width
, False)
688 if self
.operator
== "s":
689 return Shape(a_width
, True)
690 elif len(op_shapes
) == 2:
691 (a_width
, a_signed
), (b_width
, b_signed
) = op_shapes
692 if self
.operator
in ("+", "-"):
693 width
, signed
= _bitwise_binary_shape(*op_shapes
)
694 return Shape(width
+ 1, signed
)
695 if self
.operator
== "*":
696 return Shape(a_width
+ b_width
, a_signed
or b_signed
)
697 if self
.operator
in ("//", "%"):
699 return Shape(a_width
, a_signed
)
700 if self
.operator
in ("<", "<=", "==", "!=", ">", ">="):
701 return Shape(1, False)
702 if self
.operator
in ("&", "^", "|"):
703 return _bitwise_binary_shape(*op_shapes
)
704 if self
.operator
== "<<":
706 return Shape(a_width
+ 2 ** b_width
- 1, a_signed
)
707 if self
.operator
== ">>":
709 return Shape(a_width
, a_signed
)
710 elif len(op_shapes
) == 3:
711 if self
.operator
== "m":
712 s_shape
, a_shape
, b_shape
= op_shapes
713 return _bitwise_binary_shape(a_shape
, b_shape
)
714 raise NotImplementedError("Operator {}/{} not implemented"
715 .format(self
.operator
, len(op_shapes
))) # :nocov:
717 def _rhs_signals(self
):
718 return union(op
._rhs
_signals
() for op
in self
.operands
)
721 return "({} {})".format(self
.operator
, " ".join(map(repr, self
.operands
)))
724 def Mux(sel
, val1
, val0
):
725 """Choose between two values.
738 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
740 sel
= Value
.cast(sel
)
743 return Operator("m", [sel
, val1
, val0
])
748 def __init__(self
, value
, start
, stop
, *, src_loc_at
=0):
749 if not isinstance(start
, int):
750 raise TypeError("Slice start must be an integer, not {!r}".format(start
))
751 if not isinstance(stop
, int):
752 raise TypeError("Slice stop must be an integer, not {!r}".format(stop
))
755 if start
not in range(-(n
+1), n
+1):
756 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
759 if stop
not in range(-(n
+1), n
+1):
760 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop
, n
))
764 raise IndexError("Slice start {} must be less than slice stop {}".format(start
, stop
))
766 super().__init
__(src_loc_at
=src_loc_at
)
767 self
.value
= Value
.cast(value
)
772 return Shape(self
.stop
- self
.start
)
774 def _lhs_signals(self
):
775 return self
.value
._lhs
_signals
()
777 def _rhs_signals(self
):
778 return self
.value
._rhs
_signals
()
781 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.stop
)
786 def __init__(self
, value
, offset
, width
, stride
=1, *, src_loc_at
=0):
787 if not isinstance(width
, int) or width
< 0:
788 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width
))
789 if not isinstance(stride
, int) or stride
<= 0:
790 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride
))
792 super().__init
__(src_loc_at
=src_loc_at
)
794 self
.offset
= Value
.cast(offset
)
799 return Shape(self
.width
)
801 def _lhs_signals(self
):
802 return self
.value
._lhs
_signals
()
804 def _rhs_signals(self
):
805 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
808 return "(part {} {} {} {})".format(repr(self
.value
), repr(self
.offset
),
809 self
.width
, self
.stride
)
814 """Concatenate values.
816 Form a compound ``Value`` from several smaller ones by concatenation.
817 The first argument occupies the lower bits of the result.
818 The return value can be used on either side of an assignment, that
819 is, the concatenated value can be used as an argument on the RHS or
820 as a target on the LHS. If it is used on the LHS, it must solely
821 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
822 meeting these properties. The bit length of the return value is the sum of
823 the bit lengths of the arguments::
825 len(Cat(args)) == sum(len(arg) for arg in args)
829 *args : Values or iterables of Values, inout
830 ``Value`` s to be concatenated.
835 Resulting ``Value`` obtained by concatentation.
837 def __init__(self
, *args
, src_loc_at
=0):
838 super().__init
__(src_loc_at
=src_loc_at
)
839 self
.parts
= [Value
.cast(v
) for v
in flatten(args
)]
842 return Shape(sum(len(part
) for part
in self
.parts
))
844 def _lhs_signals(self
):
845 return union((part
._lhs
_signals
() for part
in self
.parts
), start
=SignalSet())
847 def _rhs_signals(self
):
848 return union((part
._rhs
_signals
() for part
in self
.parts
), start
=SignalSet())
852 for part
in reversed(self
.parts
):
854 value |
= part
._as
_const
()
858 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
865 An input value is replicated (repeated) several times
866 to be used on the RHS of assignments::
868 len(Repl(s, n)) == len(s) * n
873 Input value to be replicated.
875 Number of replications.
882 def __init__(self
, value
, count
, *, src_loc_at
=0):
883 if not isinstance(count
, int) or count
< 0:
884 raise TypeError("Replication count must be a non-negative integer, not {!r}"
887 super().__init
__(src_loc_at
=src_loc_at
)
888 self
.value
= Value
.cast(value
)
892 return Shape(len(self
.value
) * self
.count
)
894 def _rhs_signals(self
):
895 return self
.value
._rhs
_signals
()
898 return "(repl {!r} {})".format(self
.value
, self
.count
)
902 class Signal(Value
, DUID
):
903 """A varying integer value.
907 shape : ``Shape``-castable object or None
908 Specification for the number of bits in this ``Signal`` and its signedness (whether it
909 can represent negative values). See ``Shape.cast`` for details.
910 If not specified, ``shape`` defaults to 1-bit and non-signed.
912 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
913 name this ``Signal`` is assigned to.
914 reset : int or integral Enum
915 Reset (synchronous) or default (combinatorial) value.
916 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
917 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
918 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
919 assumes its ``reset`` value. Defaults to 0.
921 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
922 The ``reset`` value is only used as a combinatorial default or as the initial value.
923 Defaults to ``False``.
925 Dictionary of synthesis attributes.
926 decoder : function or Enum
927 A function converting integer signal values to human-readable strings (e.g. FSM state
928 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
929 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
943 def __init__(self
, shape
=None, *, name
=None, reset
=0, reset_less
=False,
944 attrs
=None, decoder
=None, src_loc_at
=0):
945 super().__init
__(src_loc_at
=src_loc_at
)
947 if name
is not None and not isinstance(name
, str):
948 raise TypeError("Name must be a string, not {!r}".format(name
))
949 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$signal")
953 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
955 if isinstance(reset
, Enum
):
957 if not isinstance(reset
, int):
958 raise TypeError("Reset value has to be an int or an integral Enum")
960 reset_width
= bits_for(reset
, self
.signed
)
961 if reset
!= 0 and reset_width
> self
.width
:
962 warnings
.warn("Reset value {!r} requires {} bits to represent, but the signal "
964 .format(reset
, reset_width
, self
.width
),
965 SyntaxWarning, stacklevel
=2 + src_loc_at
)
968 self
.reset_less
= bool(reset_less
)
970 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
972 if decoder
is None and isinstance(shape
, type) and issubclass(shape
, Enum
):
974 if isinstance(decoder
, type) and issubclass(decoder
, Enum
):
975 def enum_decoder(value
):
977 return "{0.name:}/{0.value:}".format(decoder(value
))
980 self
.decoder
= enum_decoder
981 self
._enum
_class
= decoder
983 self
.decoder
= decoder
984 self
._enum
_class
= None
986 # Not a @classmethod because nmigen.compat requires it.
988 def like(other
, *, name
=None, name_suffix
=None, src_loc_at
=0, **kwargs
):
989 """Create Signal based on another.
994 Object to base this Signal on.
998 elif name_suffix
is not None:
999 new_name
= other
.name
+ str(name_suffix
)
1001 new_name
= tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$like")
1002 kw
= dict(shape
=Value
.cast(other
).shape(), name
=new_name
)
1003 if isinstance(other
, Signal
):
1004 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
1005 attrs
=other
.attrs
, decoder
=other
.decoder
)
1007 return Signal(**kw
, src_loc_at
=1 + src_loc_at
)
1010 return Shape(self
.width
, self
.signed
)
1012 def _lhs_signals(self
):
1013 return SignalSet((self
,))
1015 def _rhs_signals(self
):
1016 return SignalSet((self
,))
1019 return "(sig {})".format(self
.name
)
1023 class ClockSignal(Value
):
1024 """Clock signal for a clock domain.
1026 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
1027 All of these signals ultimately refer to the same signal, but they can be manipulated
1028 independently of the clock domain, even before the clock domain is created.
1033 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
1035 def __init__(self
, domain
="sync", *, src_loc_at
=0):
1036 super().__init
__(src_loc_at
=src_loc_at
)
1037 if not isinstance(domain
, str):
1038 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1039 if domain
== "comb":
1040 raise ValueError("Domain '{}' does not have a clock".format(domain
))
1041 self
.domain
= domain
1046 def _lhs_signals(self
):
1047 return SignalSet((self
,))
1049 def _rhs_signals(self
):
1050 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
1053 return "(clk {})".format(self
.domain
)
1057 class ResetSignal(Value
):
1058 """Reset signal for a clock domain.
1060 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
1061 All of these signals ultimately refer to the same signal, but they can be manipulated
1062 independently of the clock domain, even before the clock domain is created.
1067 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
1068 allow_reset_less : bool
1069 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
1071 def __init__(self
, domain
="sync", allow_reset_less
=False, *, src_loc_at
=0):
1072 super().__init
__(src_loc_at
=src_loc_at
)
1073 if not isinstance(domain
, str):
1074 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1075 if domain
== "comb":
1076 raise ValueError("Domain '{}' does not have a reset".format(domain
))
1077 self
.domain
= domain
1078 self
.allow_reset_less
= allow_reset_less
1083 def _lhs_signals(self
):
1084 return SignalSet((self
,))
1086 def _rhs_signals(self
):
1087 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
1090 return "(rst {})".format(self
.domain
)
1093 class Array(MutableSequence
):
1094 """Addressable multiplexer.
1096 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
1099 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
1100 assignments, provided that all elements of the array are values. The array proxy also supports
1101 attribute access and further indexing, each returning another array proxy; this means that
1102 the results of indexing into arrays, arrays of records, and arrays of arrays can all
1103 be used as first-class values.
1105 It is an error to change an array or any of its elements after an array proxy was created.
1106 Changing the array directly will raise an exception. However, it is not possible to detect
1107 the elements being modified; if an element's attribute or element is modified after the proxy
1108 for it has been created, the proxy will refer to stale data.
1115 gpios = Array(Signal() for _ in range(10))
1117 m.d.sync += gpios[bus.addr].eq(bus.w_data)
1119 m.d.sync += bus.r_data.eq(gpios[bus.addr])
1121 Multidimensional array::
1123 mult = Array(Array(x * y for y in range(10)) for x in range(10))
1124 a = Signal.range(10)
1125 b = Signal.range(10)
1127 m.d.comb += r.eq(mult[a][b])
1135 buses = Array(Record(layout) for busno in range(4))
1136 master = Record(layout)
1138 buses[sel].r_en.eq(master.r_en),
1139 master.r_data.eq(buses[sel].r_data),
1142 def __init__(self
, iterable
=()):
1143 self
._inner
= list(iterable
)
1144 self
._proxy
_at
= None
1145 self
._mutable
= True
1147 def __getitem__(self
, index
):
1148 if isinstance(index
, Value
):
1150 self
._proxy
_at
= tracer
.get_src_loc()
1151 self
._mutable
= False
1152 return ArrayProxy(self
, index
)
1154 return self
._inner
[index
]
1157 return len(self
._inner
)
1159 def _check_mutability(self
):
1160 if not self
._mutable
:
1161 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1162 "at {}:{}".format(*self
._proxy
_at
))
1164 def __setitem__(self
, index
, value
):
1165 self
._check
_mutability
()
1166 self
._inner
[index
] = value
1168 def __delitem__(self
, index
):
1169 self
._check
_mutability
()
1170 del self
._inner
[index
]
1172 def insert(self
, index
, value
):
1173 self
._check
_mutability
()
1174 self
._inner
.insert(index
, value
)
1177 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
1178 ", ".join(map(repr, self
._inner
)))
1182 class ArrayProxy(Value
):
1183 def __init__(self
, elems
, index
, *, src_loc_at
=0):
1184 super().__init
__(src_loc_at
=1 + src_loc_at
)
1186 self
.index
= Value
.cast(index
)
1188 def __getattr__(self
, attr
):
1189 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
1191 def __getitem__(self
, index
):
1192 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
1194 def _iter_as_values(self
):
1195 return (Value
.cast(elem
) for elem
in self
.elems
)
1198 unsigned_width
= signed_width
= 0
1199 has_unsigned
= has_signed
= False
1200 for elem_width
, elem_signed
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
1203 signed_width
= max(signed_width
, elem_width
)
1206 unsigned_width
= max(unsigned_width
, elem_width
)
1207 # The shape of the proxy must be such that it preserves the mathematical value of the array
1208 # elements. I.e., shape-wise, an array proxy must be identical to an equivalent mux tree.
1209 # To ensure this holds, if the array contains both signed and unsigned values, make sure
1210 # that every unsigned value is zero-extended by at least one bit.
1211 if has_signed
and has_unsigned
and unsigned_width
>= signed_width
:
1212 # Array contains both signed and unsigned values, and at least one of the unsigned
1213 # values won't be zero-extended otherwise.
1214 return signed(unsigned_width
+ 1)
1216 # Array contains values of the same signedness, or else all of the unsigned values
1217 # are zero-extended.
1218 return Shape(max(unsigned_width
, signed_width
), has_signed
)
1220 def _lhs_signals(self
):
1221 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()),
1225 def _rhs_signals(self
):
1226 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()),
1228 return self
.index
._rhs
_signals
() | signals
1231 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
1234 # TODO(nmigen-0.4): remove
1235 class UserValue(Value
):
1236 """Value with custom lowering.
1238 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1239 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1240 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1241 value when required.
1243 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1244 nMigen's view of representation of all values stays internally consistent. If the class
1245 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1246 it is not mutated in a way that changes its representation.
1248 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1249 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1250 * Querying the shape using ``.shape()`` or ``len()``;
1251 * Creating a similarly shaped signal using ``Signal.like``;
1252 * Indexing or iterating through individual bits;
1253 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1255 @deprecated("instead of `UserValue`, use `ValueCastable`", stacklevel
=3)
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
()
1283 class ValueCastable
:
1284 """Base class for classes which can be cast to Values.
1286 A ``ValueCastable`` can be cast to ``Value``, meaning its precise representation does not have
1287 to be immediately known. This is useful in certain metaprogramming scenarios. Instead of
1288 providing fixed semantics upfront, it is kept abstract for as long as possible, only being
1289 cast to a concrete nMigen value when required.
1291 Note that it is necessary to ensure that nMigen's view of representation of all values stays
1292 internally consistent. The class deriving from ``ValueCastable`` must decorate the ``as_value``
1293 method with the ``lowermethod`` decorator, which ensures that all calls to ``as_value`` return
1294 the same ``Value`` representation. If the class deriving from ``ValueCastable`` is mutable,
1295 it is up to the user to ensure that it is not mutated in a way that changes its representation
1296 after the first call to ``as_value``.
1298 def __new__(cls
, *args
, **kwargs
):
1299 self
= super().__new
__(cls
)
1300 if not hasattr(self
, "as_value"):
1301 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must override "
1302 "the `as_value` method")
1304 if not hasattr(self
.as_value
, "_ValueCastable__memoized"):
1305 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must decorate "
1306 "the `as_value` method with the `ValueCastable.lowermethod` decorator")
1310 def lowermethod(func
):
1311 """Decorator to memoize lowering methods.
1313 Ensures the decorated method is called only once, with subsequent method calls returning the
1314 object returned by the first first method call.
1316 This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` subclasses.
1317 This is to ensure that nMigen's view of representation of all values stays internally
1320 @functools.wraps(func
)
1321 def wrapper_memoized(self
, *args
, **kwargs
):
1322 if not hasattr(self
, "_ValueCastable__lowered_to"):
1323 self
.__lowered
_to
= func(self
, *args
, **kwargs
)
1324 return self
.__lowered
_to
1325 wrapper_memoized
.__memoized
= True
1326 return wrapper_memoized
1330 class Sample(Value
):
1331 """Value from the past.
1333 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1334 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1335 to the value of the expression calculated as if each signal had its reset value.
1337 def __init__(self
, expr
, clocks
, domain
, *, src_loc_at
=0):
1338 super().__init
__(src_loc_at
=1 + src_loc_at
)
1339 self
.value
= Value
.cast(expr
)
1340 self
.clocks
= int(clocks
)
1341 self
.domain
= domain
1342 if not isinstance(self
.value
, (Const
, Signal
, ClockSignal
, ResetSignal
, Initial
)):
1343 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1344 .format(self
.value
))
1346 raise ValueError("Cannot sample a value {} cycles in the future"
1347 .format(-self
.clocks
))
1348 if not (self
.domain
is None or isinstance(self
.domain
, str)):
1349 raise TypeError("Domain name must be a string or None, not {!r}"
1350 .format(self
.domain
))
1353 return self
.value
.shape()
1355 def _rhs_signals(self
):
1356 return SignalSet((self
,))
1359 return "(sample {!r} @ {}[{}])".format(
1360 self
.value
, "<default>" if self
.domain
is None else self
.domain
, self
.clocks
)
1363 def Past(expr
, clocks
=1, domain
=None):
1364 return Sample(expr
, clocks
, domain
)
1367 def Stable(expr
, clocks
=0, domain
=None):
1368 return Sample(expr
, clocks
+ 1, domain
) == Sample(expr
, clocks
, domain
)
1371 def Rose(expr
, clocks
=0, domain
=None):
1372 return ~
Sample(expr
, clocks
+ 1, domain
) & Sample(expr
, clocks
, domain
)
1375 def Fell(expr
, clocks
=0, domain
=None):
1376 return Sample(expr
, clocks
+ 1, domain
) & ~
Sample(expr
, clocks
, domain
)
1380 class Initial(Value
):
1381 """Start indicator, for model checking.
1383 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1385 def __init__(self
, *, src_loc_at
=0):
1386 super().__init
__(src_loc_at
=src_loc_at
)
1391 def _rhs_signals(self
):
1392 return SignalSet((self
,))
1398 class _StatementList(list):
1400 return "({})".format(" ".join(map(repr, self
)))
1404 def __init__(self
, *, src_loc_at
=0):
1405 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
1409 if isinstance(obj
, Iterable
):
1410 return _StatementList(sum((Statement
.cast(e
) for e
in obj
), []))
1412 if isinstance(obj
, Statement
):
1413 return _StatementList([obj
])
1415 raise TypeError("Object {!r} is not an nMigen statement".format(obj
))
1419 class Assign(Statement
):
1420 def __init__(self
, lhs
, rhs
, *, src_loc_at
=0):
1421 super().__init
__(src_loc_at
=src_loc_at
)
1422 self
.lhs
= Value
.cast(lhs
)
1423 self
.rhs
= Value
.cast(rhs
)
1425 def _lhs_signals(self
):
1426 return self
.lhs
._lhs
_signals
()
1428 def _rhs_signals(self
):
1429 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
1432 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
1435 class UnusedProperty(UnusedMustUse
):
1439 class Property(Statement
, MustUse
):
1440 _MustUse__warning
= UnusedProperty
1442 def __init__(self
, test
, *, _check
=None, _en
=None, src_loc_at
=0):
1443 super().__init
__(src_loc_at
=src_loc_at
)
1444 self
.test
= Value
.cast(test
)
1445 self
._check
= _check
1447 if self
._check
is None:
1448 self
._check
= Signal(reset_less
=True, name
="${}$check".format(self
._kind
))
1449 self
._check
.src_loc
= self
.src_loc
1451 self
._en
= Signal(reset_less
=True, name
="${}$en".format(self
._kind
))
1452 self
._en
.src_loc
= self
.src_loc
1454 def _lhs_signals(self
):
1455 return SignalSet((self
._en
, self
._check
))
1457 def _rhs_signals(self
):
1458 return self
.test
._rhs
_signals
()
1461 return "({} {!r})".format(self
._kind
, self
.test
)
1465 class Assert(Property
):
1470 class Assume(Property
):
1475 class Cover(Property
):
1480 class Switch(Statement
):
1481 def __init__(self
, test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1483 super().__init
__(src_loc_at
=src_loc_at
)
1485 # Switch is a bit special in terms of location tracking because it is usually created
1486 # long after the control has left the statement that directly caused its creation.
1487 self
.src_loc
= src_loc
1488 # Switch is also a bit special in that its parts also have location information. It can't
1489 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1490 self
.case_src_locs
= {}
1492 self
.test
= Value
.cast(test
)
1493 self
.cases
= OrderedDict()
1494 for orig_keys
, stmts
in cases
.items():
1495 # Map: None -> (); key -> (key,); (key...) -> (key...)
1499 if not isinstance(keys
, tuple):
1501 # Map: 2 -> "0010"; "0010" -> "0010"
1503 key_mask
= (1 << len(self
.test
)) - 1
1505 if isinstance(key
, str):
1506 key
= "".join(key
.split()) # remove whitespace
1507 elif isinstance(key
, int):
1508 key
= format(key
& key_mask
, "b").rjust(len(self
.test
), "0")
1509 elif isinstance(key
, Enum
):
1510 key
= format(key
.value
& key_mask
, "b").rjust(len(self
.test
), "0")
1512 raise TypeError("Object {!r} cannot be used as a switch key"
1514 assert len(key
) == len(self
.test
)
1515 new_keys
= (*new_keys
, key
)
1516 if not isinstance(stmts
, Iterable
):
1518 self
.cases
[new_keys
] = Statement
.cast(stmts
)
1519 if orig_keys
in case_src_locs
:
1520 self
.case_src_locs
[new_keys
] = case_src_locs
[orig_keys
]
1522 def _lhs_signals(self
):
1523 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1527 def _rhs_signals(self
):
1528 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1530 return self
.test
._rhs
_signals
() | signals
1533 def case_repr(keys
, stmts
):
1534 stmts_repr
= " ".join(map(repr, stmts
))
1536 return "(default {})".format(stmts_repr
)
1537 elif len(keys
) == 1:
1538 return "(case {} {})".format(keys
[0], stmts_repr
)
1540 return "(case ({}) {})".format(" ".join(keys
), stmts_repr
)
1541 case_reprs
= [case_repr(keys
, stmts
) for keys
, stmts
in self
.cases
.items()]
1542 return "(switch {!r} {})".format(self
.test
, " ".join(case_reprs
))
1545 class _MappedKeyCollection(metaclass
=ABCMeta
):
1547 def _map_key(self
, key
):
1551 def _unmap_key(self
, key
):
1555 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
1556 def __init__(self
, pairs
=()):
1557 self
._storage
= OrderedDict()
1558 for key
, value
in pairs
:
1561 def __getitem__(self
, key
):
1562 key
= None if key
is None else self
._map
_key
(key
)
1563 return self
._storage
[key
]
1565 def __setitem__(self
, key
, value
):
1566 key
= None if key
is None else self
._map
_key
(key
)
1567 self
._storage
[key
] = value
1569 def __delitem__(self
, key
):
1570 key
= None if key
is None else self
._map
_key
(key
)
1571 del self
._storage
[key
]
1574 for key
in self
._storage
:
1578 yield self
._unmap
_key
(key
)
1580 def __eq__(self
, other
):
1581 if not isinstance(other
, type(self
)):
1583 if len(self
) != len(other
):
1585 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
1588 if self
._storage
[ak
] != other
._storage
[bk
]:
1593 return len(self
._storage
)
1596 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
1597 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
1601 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
1602 def __init__(self
, elements
=()):
1603 self
._storage
= OrderedDict()
1604 for elem
in elements
:
1607 def add(self
, value
):
1608 self
._storage
[self
._map
_key
(value
)] = None
1610 def update(self
, values
):
1611 for value
in values
:
1614 def discard(self
, value
):
1616 del self
._storage
[self
._map
_key
(value
)]
1618 def __contains__(self
, value
):
1619 return self
._map
_key
(value
) in self
._storage
1622 for key
in [k
for k
in self
._storage
]:
1623 yield self
._unmap
_key
(key
)
1626 return len(self
._storage
)
1629 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
1630 ", ".join(repr(x
) for x
in self
))
1634 def __init__(self
, value
):
1635 self
.value
= Value
.cast(value
)
1636 if isinstance(self
.value
, Const
):
1637 self
._hash
= hash(self
.value
.value
)
1638 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1639 self
._hash
= hash(self
.value
.duid
)
1640 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1641 self
._hash
= hash(self
.value
.domain
)
1642 elif isinstance(self
.value
, Operator
):
1643 self
._hash
= hash((self
.value
.operator
,
1644 tuple(ValueKey(o
) for o
in self
.value
.operands
)))
1645 elif isinstance(self
.value
, Slice
):
1646 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.stop
))
1647 elif isinstance(self
.value
, Part
):
1648 self
._hash
= hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
1649 self
.value
.width
, self
.value
.stride
))
1650 elif isinstance(self
.value
, Cat
):
1651 self
._hash
= hash(tuple(ValueKey(o
) for o
in self
.value
.parts
))
1652 elif isinstance(self
.value
, ArrayProxy
):
1653 self
._hash
= hash((ValueKey(self
.value
.index
),
1654 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
1655 elif isinstance(self
.value
, Sample
):
1656 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.clocks
, self
.value
.domain
))
1657 elif isinstance(self
.value
, Initial
):
1660 raise TypeError("Object {!r} cannot be used as a key in value collections"
1661 .format(self
.value
))
1666 def __eq__(self
, other
):
1667 if type(other
) is not ValueKey
:
1669 if type(self
.value
) is not type(other
.value
):
1672 if isinstance(self
.value
, Const
):
1673 return self
.value
.value
== other
.value
.value
1674 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1675 return self
.value
is other
.value
1676 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1677 return self
.value
.domain
== other
.value
.domain
1678 elif isinstance(self
.value
, Operator
):
1679 return (self
.value
.operator
== other
.value
.operator
and
1680 len(self
.value
.operands
) == len(other
.value
.operands
) and
1681 all(ValueKey(a
) == ValueKey(b
)
1682 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1683 elif isinstance(self
.value
, Slice
):
1684 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1685 self
.value
.start
== other
.value
.start
and
1686 self
.value
.stop
== other
.value
.stop
)
1687 elif isinstance(self
.value
, Part
):
1688 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1689 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1690 self
.value
.width
== other
.value
.width
and
1691 self
.value
.stride
== other
.value
.stride
)
1692 elif isinstance(self
.value
, Cat
):
1693 return all(ValueKey(a
) == ValueKey(b
)
1694 for a
, b
in zip(self
.value
.parts
, other
.value
.parts
))
1695 elif isinstance(self
.value
, ArrayProxy
):
1696 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1697 len(self
.value
.elems
) == len(other
.value
.elems
) and
1698 all(ValueKey(a
) == ValueKey(b
)
1699 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1700 other
.value
._iter
_as
_values
())))
1701 elif isinstance(self
.value
, Sample
):
1702 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1703 self
.value
.clocks
== other
.value
.clocks
and
1704 self
.value
.domain
== self
.value
.domain
)
1705 elif isinstance(self
.value
, Initial
):
1708 raise TypeError("Object {!r} cannot be used as a key in value collections"
1709 .format(self
.value
))
1711 def __lt__(self
, other
):
1712 if not isinstance(other
, ValueKey
):
1714 if type(self
.value
) != type(other
.value
):
1717 if isinstance(self
.value
, Const
):
1718 return self
.value
< other
.value
1719 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1720 return self
.value
.duid
< other
.value
.duid
1721 elif isinstance(self
.value
, Slice
):
1722 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1723 self
.value
.start
< other
.value
.start
and
1724 self
.value
.end
< other
.value
.end
)
1726 raise TypeError("Object {!r} cannot be used as a key in value collections")
1729 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1732 class ValueDict(_MappedKeyDict
):
1734 _unmap_key
= lambda self
, key
: key
.value
1737 class ValueSet(_MappedKeySet
):
1739 _unmap_key
= lambda self
, key
: key
.value
1743 def __init__(self
, signal
):
1744 self
.signal
= signal
1745 if isinstance(signal
, Signal
):
1746 self
._intern
= (0, signal
.duid
)
1747 elif type(signal
) is ClockSignal
:
1748 self
._intern
= (1, signal
.domain
)
1749 elif type(signal
) is ResetSignal
:
1750 self
._intern
= (2, signal
.domain
)
1752 raise TypeError("Object {!r} is not an nMigen signal".format(signal
))
1755 return hash(self
._intern
)
1757 def __eq__(self
, other
):
1758 if type(other
) is not SignalKey
:
1760 return self
._intern
== other
._intern
1762 def __lt__(self
, other
):
1763 if type(other
) is not SignalKey
:
1764 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal
))
1765 return self
._intern
< other
._intern
1768 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1771 class SignalDict(_MappedKeyDict
):
1772 _map_key
= SignalKey
1773 _unmap_key
= lambda self
, key
: key
.signal
1776 class SignalSet(_MappedKeySet
):
1777 _map_key
= SignalKey
1778 _unmap_key
= lambda self
, key
: key
.signal