e645dc6d4ec246eef09f52a8a7d8de6129abfb68
1 from abc
import ABCMeta
, abstractmethod
4 from collections
import OrderedDict
5 from collections
.abc
import Iterable
, MutableMapping
, MutableSet
, MutableSequence
7 from itertools
import chain
10 from .._utils
import *
11 from .._unused
import *
15 "Shape", "signed", "unsigned",
16 "Value", "Const", "C", "AnyConst", "AnySeq", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
17 "Array", "ArrayProxy",
18 "_InternalSwitch", "_InternalAssign", "_InternalRepl",
19 "Signal", "ClockSignal", "ResetSignal",
20 "UserValue", "ValueCastable",
21 "Sample", "Past", "Stable", "Rose", "Fell", "Initial",
22 "Statement", "Switch",
23 "Property", "Assign", "Assert", "Assume", "Cover",
24 "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "SignalSet",
29 """Deterministic Unique IDentifier."""
32 self
.duid
= DUID
.__next
_uid
37 """Bit width and signedness of a value.
39 A ``Shape`` can be constructed using:
40 * explicit bit width and signedness;
41 * aliases :func:`signed` and :func:`unsigned`;
42 * casting from a variety of objects.
44 A ``Shape`` can be cast from:
45 * an integer, where the integer specifies the bit width;
46 * a range, where the result is wide enough to represent any element of the range, and is
47 signed if any element of the range is signed;
48 * an :class:`Enum` with all integer members or :class:`IntEnum`, where the result is wide
49 enough to represent any member of the enumeration, and is signed if any member of
50 the enumeration is signed.
55 The number of bits in the representation, including the sign bit (if any).
57 If ``False``, the value is unsigned. If ``True``, the value is signed two's complement.
59 def __init__(self
, width
=1, signed
=False):
60 if not isinstance(width
, int) or width
< 0:
61 raise TypeError("Width must be a non-negative integer, not {!r}"
67 return iter((self
.width
, self
.signed
))
70 def cast(obj
, *, src_loc_at
=0):
71 if isinstance(obj
, Shape
):
73 if isinstance(obj
, int):
75 if isinstance(obj
, tuple):
77 warnings
.warn("instead of `{tuple}`, use `{constructor}({width})`"
78 .format(constructor
="signed" if signed
else "unsigned", width
=width
,
80 DeprecationWarning, stacklevel
=2 + src_loc_at
)
81 return Shape(width
, signed
)
82 if isinstance(obj
, range):
84 return Shape(0, obj
.start
< 0)
85 signed
= obj
.start
< 0 or (obj
.stop
- obj
.step
) < 0
86 width
= max(bits_for(obj
.start
, signed
),
87 bits_for(obj
.stop
- obj
.step
, signed
))
88 return Shape(width
, signed
)
89 if isinstance(obj
, type) and issubclass(obj
, Enum
):
90 min_value
= min(member
.value
for member
in obj
)
91 max_value
= max(member
.value
for member
in obj
)
92 if not isinstance(min_value
, int) or not isinstance(max_value
, int):
93 raise TypeError("Only enumerations with integer values can be used "
95 signed
= min_value
< 0 or max_value
< 0
96 width
= max(bits_for(min_value
, signed
), bits_for(max_value
, signed
))
97 return Shape(width
, signed
)
98 raise TypeError("Object {!r} cannot be used as value shape".format(obj
))
102 return "signed({})".format(self
.width
)
104 return "unsigned({})".format(self
.width
)
106 def __eq__(self
, other
):
107 if isinstance(other
, tuple) and len(other
) == 2:
108 width
, signed
= other
109 if isinstance(width
, int) and isinstance(signed
, bool):
110 return self
.width
== width
and self
.signed
== signed
112 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
115 if not isinstance(other
, Shape
):
116 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
119 return self
.width
== other
.width
and self
.signed
== other
.signed
123 """Shorthand for ``Shape(width, signed=False)``."""
124 return Shape(width
, signed
=False)
128 """Shorthand for ``Shape(width, signed=True)``."""
129 return Shape(width
, signed
=True)
132 class Value(metaclass
=ABCMeta
):
135 """Converts ``obj`` to an nMigen value.
137 Booleans and integers are wrapped into a :class:`Const`. Enumerations whose members are
138 all integers are converted to a :class:`Const` with a shape that fits every member.
140 if isinstance(obj
, Value
):
142 if isinstance(obj
, int):
144 if isinstance(obj
, Enum
):
145 return Const(obj
.value
, Shape
.cast(type(obj
)))
146 if isinstance(obj
, ValueCastable
):
147 return obj
.as_value()
148 raise TypeError("Object {!r} cannot be converted to an nMigen value".format(obj
))
150 def __init__(self
, *, src_loc_at
=0):
152 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
154 def __Repl__(self
, count
, *, src_loc_at
=0):
155 return _InternalRepl(self
, count
, src_loc_at
=src_loc_at
)
157 def __Mux__(self
, val1
, val0
):
158 return _InternalMux(self
, val1
, val0
)
160 def __Switch__(self
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
161 return _InternalSwitch(self
, cases
, src_loc
=src_loc
,
162 src_loc_at
=src_loc_at
,
163 case_src_locs
=case_src_locs
)
165 def __Assign__(self
, rhs
, *, src_loc_at
=0):
166 return _InternalAssign(self
, rhs
, src_loc_at
=src_loc_at
)
169 raise TypeError("Attempted to convert nMigen value to Python boolean")
171 def __invert__(self
):
172 return Operator("~", [self
])
174 return Operator("-", [self
])
176 def __add__(self
, other
):
177 return Operator("+", [self
, other
])
178 def __radd__(self
, other
):
179 return Operator("+", [other
, self
])
180 def __sub__(self
, other
):
181 return Operator("-", [self
, other
])
182 def __rsub__(self
, other
):
183 return Operator("-", [other
, self
])
185 def __mul__(self
, other
):
186 return Operator("*", [self
, other
])
187 def __rmul__(self
, other
):
188 return Operator("*", [other
, self
])
190 def __check_divisor(self
):
191 width
, signed
= self
.shape()
193 # Python's division semantics and Verilog's division semantics differ for negative
194 # divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
195 # completely by prohibiting such division operations.
196 raise NotImplementedError("Division by a signed value is not supported")
197 def __mod__(self
, other
):
198 other
= Value
.cast(other
)
199 other
.__check
_divisor
()
200 return Operator("%", [self
, other
])
201 def __rmod__(self
, other
):
202 self
.__check
_divisor
()
203 return Operator("%", [other
, self
])
204 def __floordiv__(self
, other
):
205 other
= Value
.cast(other
)
206 other
.__check
_divisor
()
207 return Operator("//", [self
, other
])
208 def __rfloordiv__(self
, other
):
209 self
.__check
_divisor
()
210 return Operator("//", [other
, self
])
212 def __check_shamt(self
):
213 width
, signed
= self
.shape()
215 # Neither Python nor HDLs implement shifts by negative values; prohibit any shifts
216 # by a signed value to make sure the shift amount can always be interpreted as
218 raise TypeError("Shift amount must be unsigned")
219 def __lshift__(self
, other
):
220 other
= Value
.cast(other
)
221 other
.__check
_shamt
()
222 return Operator("<<", [self
, other
])
223 def __rlshift__(self
, other
):
225 return Operator("<<", [other
, self
])
226 def __rshift__(self
, other
):
227 other
= Value
.cast(other
)
228 other
.__check
_shamt
()
229 return Operator(">>", [self
, other
])
230 def __rrshift__(self
, other
):
232 return Operator(">>", [other
, self
])
234 def __and__(self
, other
):
235 return Operator("&", [self
, other
])
236 def __rand__(self
, other
):
237 return Operator("&", [other
, self
])
238 def __xor__(self
, other
):
239 return Operator("^", [self
, other
])
240 def __rxor__(self
, other
):
241 return Operator("^", [other
, self
])
242 def __or__(self
, other
):
243 return Operator("|", [self
, other
])
244 def __ror__(self
, other
):
245 return Operator("|", [other
, self
])
247 def __eq__(self
, other
):
248 return Operator("==", [self
, other
])
249 def __ne__(self
, other
):
250 return Operator("!=", [self
, other
])
251 def __lt__(self
, other
):
252 return Operator("<", [self
, other
])
253 def __le__(self
, other
):
254 return Operator("<=", [self
, other
])
255 def __gt__(self
, other
):
256 return Operator(">", [self
, other
])
257 def __ge__(self
, other
):
258 return Operator(">=", [self
, other
])
261 width
, signed
= self
.shape()
263 return Mux(self
>= 0, self
, -self
)
268 return self
.shape().width
270 def __getitem__(self
, key
):
272 if isinstance(key
, int):
273 if key
not in range(-n
, n
):
274 raise IndexError(f
"Index {key} is out of bounds for a {n}-bit value")
277 return Slice(self
, key
, key
+ 1)
278 elif isinstance(key
, slice):
279 start
, stop
, step
= key
.indices(n
)
281 return Cat(self
[i
] for i
in range(start
, stop
, step
))
282 return Slice(self
, start
, stop
)
284 raise TypeError("Cannot index value with {}".format(repr(key
)))
286 def as_unsigned(self
):
287 """Conversion to unsigned.
292 This ``Value`` reinterpreted as a unsigned integer.
294 return Operator("u", [self
])
297 """Conversion to signed.
302 This ``Value`` reinterpreted as a signed integer.
304 return Operator("s", [self
])
307 """Conversion to boolean.
312 ``1`` if any bits are set, ``0`` otherwise.
314 return Operator("b", [self
])
317 """Check if any bits are ``1``.
322 ``1`` if any bits are set, ``0`` otherwise.
324 return Operator("r|", [self
])
327 """Check if all bits are ``1``.
332 ``1`` if all bits are set, ``0`` otherwise.
334 return Operator("r&", [self
])
337 """Compute pairwise exclusive-or of every bit.
342 ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set.
344 return Operator("r^", [self
])
346 def implies(premise
, conclusion
):
352 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
354 return ~premise | conclusion
356 def bit_select(self
, offset
, width
):
357 """Part-select with bit granularity.
359 Selects a constant width but variable offset part of a ``Value``, such that successive
360 parts overlap by all but 1 bit.
365 Index of first selected bit.
367 Number of selected bits.
372 Selected part of the ``Value``
374 offset
= Value
.cast(offset
)
375 if type(offset
) is Const
and isinstance(width
, int):
376 return self
[offset
.value
:offset
.value
+ width
]
377 return Part(self
, offset
, width
, stride
=1, src_loc_at
=1)
379 def word_select(self
, offset
, width
):
380 """Part-select with word granularity.
382 Selects a constant width but variable offset part of a ``Value``, such that successive
383 parts do not overlap.
388 Index of first selected word.
390 Number of selected bits.
395 Selected part of the ``Value``
397 offset
= Value
.cast(offset
)
398 if type(offset
) is Const
and isinstance(width
, int):
399 return self
[offset
.value
* width
:(offset
.value
+ 1) * width
]
400 return Part(self
, offset
, width
, stride
=width
, src_loc_at
=1)
402 def matches(self
, *patterns
):
405 Matches against a set of patterns, which may be integers or bit strings, recognizing
406 the same grammar as ``Case()``.
410 patterns : int or str
411 Patterns to match against.
416 ``1`` if any pattern matches the value, ``0`` otherwise.
419 for pattern
in patterns
:
420 if not isinstance(pattern
, (int, str, Enum
)):
421 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
424 if isinstance(pattern
, str) and any(bit
not in "01- \t" for bit
in pattern
):
425 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
426 "bits, and may include whitespace"
428 if (isinstance(pattern
, str) and
429 len("".join(pattern
.split())) != len(self
)):
430 raise SyntaxError("Match pattern '{}' must have the same width as match value "
432 .format(pattern
, len(self
)))
433 if isinstance(pattern
, int) and bits_for(pattern
) > len(self
):
434 warnings
.warn("Match pattern '{:b}' is wider than match value "
435 "(which has width {}); comparison will never be true"
436 .format(pattern
, len(self
)),
437 SyntaxWarning, stacklevel
=3)
439 if isinstance(pattern
, str):
440 pattern
= "".join(pattern
.split()) # remove whitespace
441 mask
= int(pattern
.replace("0", "1").replace("-", "0"), 2)
442 pattern
= int(pattern
.replace("-", "0"), 2)
443 matches
.append((self
& mask
) == pattern
)
444 elif isinstance(pattern
, int):
445 matches
.append(self
== pattern
)
446 elif isinstance(pattern
, Enum
):
447 matches
.append(self
== pattern
.value
)
452 elif len(matches
) == 1:
455 return Cat(*matches
).any()
457 def shift_left(self
, amount
):
458 """Shift left by constant amount.
468 If the amount is positive, the input shifted left. Otherwise, the input shifted right.
470 if not isinstance(amount
, int):
471 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
473 return self
.shift_right(-amount
)
474 if self
.shape().signed
:
475 return Cat(Const(0, amount
), self
).as_signed()
477 return Cat(Const(0, amount
), self
) # unsigned
479 def shift_right(self
, amount
):
480 """Shift right by constant amount.
490 If the amount is positive, the input shifted right. Otherwise, the input shifted left.
492 if not isinstance(amount
, int):
493 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
495 return self
.shift_left(-amount
)
496 if self
.shape().signed
:
497 return self
[amount
:].as_signed()
499 return self
[amount
:] # unsigned
501 def rotate_left(self
, amount
):
502 """Rotate left by constant amount.
512 If the amount is positive, the input rotated left. Otherwise, the input rotated right.
514 if not isinstance(amount
, int):
515 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
517 return Cat(self
[-amount
:], self
[:-amount
]) # meow :3
519 def rotate_right(self
, amount
):
520 """Rotate right by constant amount.
530 If the amount is positive, the input rotated right. Otherwise, the input rotated right.
532 if not isinstance(amount
, int):
533 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
535 return Cat(self
[amount
:], self
[:amount
])
543 Value to be assigned.
548 Assignment statement that can be used in combinatorial or synchronous context.
550 return Assign(self
, value
, src_loc_at
=1)
554 """Bit width and signedness of a value.
563 >>> Signal(8).shape()
564 Shape(width=8, signed=False)
565 >>> Const(0xaa).shape()
566 Shape(width=8, signed=False)
570 def _lhs_signals(self
):
571 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
574 def _rhs_signals(self
):
578 raise TypeError("Value {!r} cannot be evaluated as constant".format(self
))
585 """A constant, literal integer value.
590 shape : int or tuple or None
591 Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
592 in this constant and whether it is signed (can represent negative values).
593 ``shape`` defaults to the minimum possible width and signedness of ``value``.
603 def normalize(value
, shape
):
604 width
, signed
= shape
605 mask
= (1 << width
) - 1
607 if signed
and value
>> (width
- 1):
611 def __init__(self
, value
, shape
=None, *, src_loc_at
=0):
612 # We deliberately do not call Value.__init__ here.
613 self
.value
= int(value
)
615 shape
= Shape(bits_for(self
.value
), signed
=self
.value
< 0)
616 elif isinstance(shape
, int):
617 shape
= Shape(shape
, signed
=self
.value
< 0)
619 shape
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
620 self
.width
, self
.signed
= shape
621 self
.value
= self
.normalize(self
.value
, shape
)
624 return Shape(self
.width
, self
.signed
)
626 def _rhs_signals(self
):
633 return "(const {}'{}d{})".format(self
.width
, "s" if self
.signed
else "", self
.value
)
636 C
= Const
# shorthand
639 class AnyValue(Value
, DUID
):
640 def __init__(self
, shape
, *, src_loc_at
=0):
641 super().__init
__(src_loc_at
=src_loc_at
)
642 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
643 if not isinstance(self
.width
, int) or self
.width
< 0:
644 raise TypeError("Width must be a non-negative integer, not {!r}"
648 return Shape(self
.width
, self
.signed
)
650 def _rhs_signals(self
):
655 class AnyConst(AnyValue
):
657 return "(anyconst {}'{})".format(self
.width
, "s" if self
.signed
else "")
661 class AnySeq(AnyValue
):
663 return "(anyseq {}'{})".format(self
.width
, "s" if self
.signed
else "")
667 class Operator(Value
):
668 def __init__(self
, operator
, operands
, *, src_loc_at
=0):
669 super().__init
__(src_loc_at
=1 + src_loc_at
)
670 self
.operator
= operator
671 self
.operands
= [Value
.cast(op
) for op
in operands
]
674 def _bitwise_binary_shape(a_shape
, b_shape
):
675 a_bits
, a_sign
= a_shape
676 b_bits
, b_sign
= b_shape
677 if not a_sign
and not b_sign
:
678 # both operands unsigned
679 return Shape(max(a_bits
, b_bits
), False)
680 elif a_sign
and b_sign
:
681 # both operands signed
682 return Shape(max(a_bits
, b_bits
), True)
683 elif not a_sign
and b_sign
:
684 # first operand unsigned (add sign bit), second operand signed
685 return Shape(max(a_bits
+ 1, b_bits
), True)
687 # first signed, second operand unsigned (add sign bit)
688 return Shape(max(a_bits
, b_bits
+ 1), True)
690 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
691 if len(op_shapes
) == 1:
692 (a_width
, a_signed
), = op_shapes
693 if self
.operator
in ("+", "~"):
694 return Shape(a_width
, a_signed
)
695 if self
.operator
== "-":
696 return Shape(a_width
+ 1, True)
697 if self
.operator
in ("b", "r|", "r&", "r^"):
698 return Shape(1, False)
699 if self
.operator
== "u":
700 return Shape(a_width
, False)
701 if self
.operator
== "s":
702 return Shape(a_width
, True)
703 elif len(op_shapes
) == 2:
704 (a_width
, a_signed
), (b_width
, b_signed
) = op_shapes
705 if self
.operator
in ("+", "-"):
706 width
, signed
= _bitwise_binary_shape(*op_shapes
)
707 return Shape(width
+ 1, signed
)
708 if self
.operator
== "*":
709 return Shape(a_width
+ b_width
, a_signed
or b_signed
)
710 if self
.operator
in ("//", "%"):
712 return Shape(a_width
, a_signed
)
713 if self
.operator
in ("<", "<=", "==", "!=", ">", ">="):
714 return Shape(1, False)
715 if self
.operator
in ("&", "^", "|"):
716 return _bitwise_binary_shape(*op_shapes
)
717 if self
.operator
== "<<":
719 return Shape(a_width
+ 2 ** b_width
- 1, a_signed
)
720 if self
.operator
== ">>":
722 return Shape(a_width
, a_signed
)
723 elif len(op_shapes
) == 3:
724 if self
.operator
== "m":
725 s_shape
, a_shape
, b_shape
= op_shapes
726 return _bitwise_binary_shape(a_shape
, b_shape
)
727 raise NotImplementedError("Operator {}/{} not implemented"
728 .format(self
.operator
, len(op_shapes
))) # :nocov:
730 def _rhs_signals(self
):
731 return union(op
._rhs
_signals
() for op
in self
.operands
)
734 return "({} {})".format(self
.operator
, " ".join(map(repr, self
.operands
)))
737 def Mux(sel
, val1
, val0
):
738 if isinstance(sel
, bool): # one instance where Mux is passed an actual bool
739 sel
= Value
.cast(sel
)
740 return sel
.__Mux
__(val1
, val0
)
743 def _InternalMux(sel
, val1
, val0
):
744 """Choose between two values.
757 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
759 sel
= Value
.cast(sel
)
762 return Operator("m", [sel
, val1
, val0
])
767 def __init__(self
, value
, start
, stop
, *, src_loc_at
=0):
768 if not isinstance(start
, int):
769 raise TypeError("Slice start must be an integer, not {!r}".format(start
))
770 if not isinstance(stop
, int):
771 raise TypeError("Slice stop must be an integer, not {!r}".format(stop
))
774 if start
not in range(-(n
+1), n
+1):
775 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
778 if stop
not in range(-(n
+1), n
+1):
779 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop
, n
))
783 raise IndexError("Slice start {} must be less than slice stop {}".format(start
, stop
))
785 super().__init
__(src_loc_at
=src_loc_at
)
786 self
.value
= Value
.cast(value
)
787 self
.start
= int(start
)
788 self
.stop
= int(stop
)
791 return Shape(self
.stop
- self
.start
)
793 def _lhs_signals(self
):
794 return self
.value
._lhs
_signals
()
796 def _rhs_signals(self
):
797 return self
.value
._rhs
_signals
()
800 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.stop
)
805 def __init__(self
, value
, offset
, width
, stride
=1, *, src_loc_at
=0):
806 if not isinstance(width
, int) or width
< 0:
807 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width
))
808 if not isinstance(stride
, int) or stride
<= 0:
809 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride
))
811 super().__init
__(src_loc_at
=src_loc_at
)
813 self
.offset
= Value
.cast(offset
)
818 return Shape(self
.width
)
820 def _lhs_signals(self
):
821 return self
.value
._lhs
_signals
()
823 def _rhs_signals(self
):
824 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
827 return "(part {} {} {} {})".format(repr(self
.value
), repr(self
.offset
),
828 self
.width
, self
.stride
)
833 """Concatenate values.
835 Form a compound ``Value`` from several smaller ones by concatenation.
836 The first argument occupies the lower bits of the result.
837 The return value can be used on either side of an assignment, that
838 is, the concatenated value can be used as an argument on the RHS or
839 as a target on the LHS. If it is used on the LHS, it must solely
840 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
841 meeting these properties. The bit length of the return value is the sum of
842 the bit lengths of the arguments::
844 len(Cat(args)) == sum(len(arg) for arg in args)
848 *args : Values or iterables of Values, inout
849 ``Value`` s to be concatenated.
854 Resulting ``Value`` obtained by concatentation.
856 def __init__(self
, *args
, src_loc_at
=0):
857 super().__init
__(src_loc_at
=src_loc_at
)
858 self
.parts
= [Value
.cast(v
) for v
in flatten(args
)]
861 return Shape(sum(len(part
) for part
in self
.parts
))
863 def _lhs_signals(self
):
864 return union((part
._lhs
_signals
() for part
in self
.parts
), start
=SignalSet())
866 def _rhs_signals(self
):
867 return union((part
._rhs
_signals
() for part
in self
.parts
), start
=SignalSet())
871 for part
in reversed(self
.parts
):
873 value |
= part
._as
_const
()
877 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
881 def Repl(value
, count
, *, src_loc_at
=0):
882 return value
.__Repl
__(count
, src_loc_at
=src_loc_at
)
885 class _InternalRepl(Value
):
888 An input value is replicated (repeated) several times
889 to be used on the RHS of assignments::
891 len(Repl(s, n)) == len(s) * n
896 Input value to be replicated.
898 Number of replications.
905 def __init__(self
, value
, count
, *, src_loc_at
=0):
906 if not isinstance(count
, int) or count
< 0:
907 raise TypeError("Replication count must be a non-negative integer, not {!r}"
910 super().__init
__(src_loc_at
=src_loc_at
)
911 self
.value
= Value
.cast(value
)
915 return Shape(len(self
.value
) * self
.count
)
917 def _rhs_signals(self
):
918 return self
.value
._rhs
_signals
()
921 return "(repl {!r} {})".format(self
.value
, self
.count
)
925 class Signal(Value
, DUID
):
926 """A varying integer value.
930 shape : ``Shape``-castable object or None
931 Specification for the number of bits in this ``Signal`` and its signedness (whether it
932 can represent negative values). See ``Shape.cast`` for details.
933 If not specified, ``shape`` defaults to 1-bit and non-signed.
935 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
936 name this ``Signal`` is assigned to.
937 reset : int or integral Enum
938 Reset (synchronous) or default (combinatorial) value.
939 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
940 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
941 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
942 assumes its ``reset`` value. Defaults to 0.
944 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
945 The ``reset`` value is only used as a combinatorial default or as the initial value.
946 Defaults to ``False``.
948 Dictionary of synthesis attributes.
949 decoder : function or Enum
950 A function converting integer signal values to human-readable strings (e.g. FSM state
951 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
952 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
966 def __init__(self
, shape
=None, *, name
=None, reset
=0, reset_less
=False,
967 attrs
=None, decoder
=None, src_loc_at
=0):
968 super().__init
__(src_loc_at
=src_loc_at
)
970 if name
is not None and not isinstance(name
, str):
971 raise TypeError("Name must be a string, not {!r}".format(name
))
972 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$signal")
976 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
978 if isinstance(reset
, Enum
):
980 if not isinstance(reset
, int):
981 raise TypeError("Reset value has to be an int or an integral Enum")
983 reset_width
= bits_for(reset
, self
.signed
)
984 if reset
!= 0 and reset_width
> self
.width
:
985 warnings
.warn("Reset value {!r} requires {} bits to represent, but the signal "
987 .format(reset
, reset_width
, self
.width
),
988 SyntaxWarning, stacklevel
=2 + src_loc_at
)
991 self
.reset_less
= bool(reset_less
)
993 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
995 if decoder
is None and isinstance(shape
, type) and issubclass(shape
, Enum
):
997 if isinstance(decoder
, type) and issubclass(decoder
, Enum
):
998 def enum_decoder(value
):
1000 return "{0.name:}/{0.value:}".format(decoder(value
))
1003 self
.decoder
= enum_decoder
1004 self
._enum
_class
= decoder
1006 self
.decoder
= decoder
1007 self
._enum
_class
= None
1009 # Not a @classmethod because nmigen.compat requires it.
1011 def like(other
, *, name
=None, name_suffix
=None, src_loc_at
=0, **kwargs
):
1012 """Create Signal based on another.
1017 Object to base this Signal on.
1019 if name
is not None:
1020 new_name
= str(name
)
1021 elif name_suffix
is not None:
1022 new_name
= other
.name
+ str(name_suffix
)
1024 new_name
= tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$like")
1025 kw
= dict(shape
=Value
.cast(other
).shape(), name
=new_name
)
1026 if isinstance(other
, Signal
):
1027 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
1028 attrs
=other
.attrs
, decoder
=other
.decoder
)
1030 return Signal(**kw
, src_loc_at
=1 + src_loc_at
)
1033 return Shape(self
.width
, self
.signed
)
1035 def _lhs_signals(self
):
1036 return SignalSet((self
,))
1038 def _rhs_signals(self
):
1039 return SignalSet((self
,))
1042 return "(sig {})".format(self
.name
)
1046 class ClockSignal(Value
):
1047 """Clock signal for a clock domain.
1049 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
1050 All of these signals ultimately refer to the same signal, but they can be manipulated
1051 independently of the clock domain, even before the clock domain is created.
1056 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
1058 def __init__(self
, domain
="sync", *, src_loc_at
=0):
1059 super().__init
__(src_loc_at
=src_loc_at
)
1060 if not isinstance(domain
, str):
1061 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1062 if domain
== "comb":
1063 raise ValueError("Domain '{}' does not have a clock".format(domain
))
1064 self
.domain
= domain
1069 def _lhs_signals(self
):
1070 return SignalSet((self
,))
1072 def _rhs_signals(self
):
1073 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
1076 return "(clk {})".format(self
.domain
)
1080 class ResetSignal(Value
):
1081 """Reset signal for a clock domain.
1083 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
1084 All of these signals ultimately refer to the same signal, but they can be manipulated
1085 independently of the clock domain, even before the clock domain is created.
1090 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
1091 allow_reset_less : bool
1092 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
1094 def __init__(self
, domain
="sync", allow_reset_less
=False, *, src_loc_at
=0):
1095 super().__init
__(src_loc_at
=src_loc_at
)
1096 if not isinstance(domain
, str):
1097 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1098 if domain
== "comb":
1099 raise ValueError("Domain '{}' does not have a reset".format(domain
))
1100 self
.domain
= domain
1101 self
.allow_reset_less
= allow_reset_less
1106 def _lhs_signals(self
):
1107 return SignalSet((self
,))
1109 def _rhs_signals(self
):
1110 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
1113 return "(rst {})".format(self
.domain
)
1116 class Array(MutableSequence
):
1117 """Addressable multiplexer.
1119 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
1122 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
1123 assignments, provided that all elements of the array are values. The array proxy also supports
1124 attribute access and further indexing, each returning another array proxy; this means that
1125 the results of indexing into arrays, arrays of records, and arrays of arrays can all
1126 be used as first-class values.
1128 It is an error to change an array or any of its elements after an array proxy was created.
1129 Changing the array directly will raise an exception. However, it is not possible to detect
1130 the elements being modified; if an element's attribute or element is modified after the proxy
1131 for it has been created, the proxy will refer to stale data.
1138 gpios = Array(Signal() for _ in range(10))
1140 m.d.sync += gpios[bus.addr].eq(bus.w_data)
1142 m.d.sync += bus.r_data.eq(gpios[bus.addr])
1144 Multidimensional array::
1146 mult = Array(Array(x * y for y in range(10)) for x in range(10))
1147 a = Signal.range(10)
1148 b = Signal.range(10)
1150 m.d.comb += r.eq(mult[a][b])
1158 buses = Array(Record(layout) for busno in range(4))
1159 master = Record(layout)
1161 buses[sel].r_en.eq(master.r_en),
1162 master.r_data.eq(buses[sel].r_data),
1165 def __init__(self
, iterable
=()):
1166 self
._inner
= list(iterable
)
1167 self
._proxy
_at
= None
1168 self
._mutable
= True
1170 def __getitem__(self
, index
):
1171 if isinstance(index
, Value
):
1173 self
._proxy
_at
= tracer
.get_src_loc()
1174 self
._mutable
= False
1175 return ArrayProxy(self
, index
)
1177 return self
._inner
[index
]
1180 return len(self
._inner
)
1182 def _check_mutability(self
):
1183 if not self
._mutable
:
1184 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1185 "at {}:{}".format(*self
._proxy
_at
))
1187 def __setitem__(self
, index
, value
):
1188 self
._check
_mutability
()
1189 self
._inner
[index
] = value
1191 def __delitem__(self
, index
):
1192 self
._check
_mutability
()
1193 del self
._inner
[index
]
1195 def insert(self
, index
, value
):
1196 self
._check
_mutability
()
1197 self
._inner
.insert(index
, value
)
1200 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
1201 ", ".join(map(repr, self
._inner
)))
1205 class ArrayProxy(Value
):
1206 def __init__(self
, elems
, index
, *, src_loc_at
=0):
1207 super().__init
__(src_loc_at
=1 + src_loc_at
)
1209 self
.index
= Value
.cast(index
)
1211 def __getattr__(self
, attr
):
1212 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
1214 def __getitem__(self
, index
):
1215 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
1217 def _iter_as_values(self
):
1218 return (Value
.cast(elem
) for elem
in self
.elems
)
1221 unsigned_width
= signed_width
= 0
1222 has_unsigned
= has_signed
= False
1223 for elem_width
, elem_signed
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
1226 signed_width
= max(signed_width
, elem_width
)
1229 unsigned_width
= max(unsigned_width
, elem_width
)
1230 # The shape of the proxy must be such that it preserves the mathematical value of the array
1231 # elements. I.e., shape-wise, an array proxy must be identical to an equivalent mux tree.
1232 # To ensure this holds, if the array contains both signed and unsigned values, make sure
1233 # that every unsigned value is zero-extended by at least one bit.
1234 if has_signed
and has_unsigned
and unsigned_width
>= signed_width
:
1235 # Array contains both signed and unsigned values, and at least one of the unsigned
1236 # values won't be zero-extended otherwise.
1237 return signed(unsigned_width
+ 1)
1239 # Array contains values of the same signedness, or else all of the unsigned values
1240 # are zero-extended.
1241 return Shape(max(unsigned_width
, signed_width
), has_signed
)
1243 def _lhs_signals(self
):
1244 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()),
1248 def _rhs_signals(self
):
1249 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()),
1251 return self
.index
._rhs
_signals
() | signals
1254 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
1257 # TODO(nmigen-0.4): remove
1258 class UserValue(Value
):
1259 """Value with custom lowering.
1261 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1262 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1263 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1264 value when required.
1266 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1267 nMigen's view of representation of all values stays internally consistent. If the class
1268 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1269 it is not mutated in a way that changes its representation.
1271 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1272 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1273 * Querying the shape using ``.shape()`` or ``len()``;
1274 * Creating a similarly shaped signal using ``Signal.like``;
1275 * Indexing or iterating through individual bits;
1276 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1278 @deprecated("instead of `UserValue`, use `ValueCastable`", stacklevel
=3)
1279 def __init__(self
, *, src_loc_at
=0):
1280 super().__init
__(src_loc_at
=1 + src_loc_at
)
1281 self
.__lowered
= None
1285 """Conversion to a concrete representation."""
1288 def _lazy_lower(self
):
1289 if self
.__lowered
is None:
1290 lowered
= self
.lower()
1291 if isinstance(lowered
, UserValue
):
1292 lowered
= lowered
._lazy
_lower
()
1293 self
.__lowered
= Value
.cast(lowered
)
1294 return self
.__lowered
1297 return self
._lazy
_lower
().shape()
1299 def _lhs_signals(self
):
1300 return self
._lazy
_lower
()._lhs
_signals
()
1302 def _rhs_signals(self
):
1303 return self
._lazy
_lower
()._rhs
_signals
()
1306 class ValueCastable
:
1307 """Base class for classes which can be cast to Values.
1309 A ``ValueCastable`` can be cast to ``Value``, meaning its precise representation does not have
1310 to be immediately known. This is useful in certain metaprogramming scenarios. Instead of
1311 providing fixed semantics upfront, it is kept abstract for as long as possible, only being
1312 cast to a concrete nMigen value when required.
1314 Note that it is necessary to ensure that nMigen's view of representation of all values stays
1315 internally consistent. The class deriving from ``ValueCastable`` must decorate the ``as_value``
1316 method with the ``lowermethod`` decorator, which ensures that all calls to ``as_value`` return
1317 the same ``Value`` representation. If the class deriving from ``ValueCastable`` is mutable,
1318 it is up to the user to ensure that it is not mutated in a way that changes its representation
1319 after the first call to ``as_value``.
1321 def __new__(cls
, *args
, **kwargs
):
1322 self
= super().__new
__(cls
)
1323 if not hasattr(self
, "as_value"):
1324 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must override "
1325 "the `as_value` method")
1327 if not hasattr(self
.as_value
, "_ValueCastable__memoized"):
1328 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must decorate "
1329 "the `as_value` method with the `ValueCastable.lowermethod` decorator")
1333 def lowermethod(func
):
1334 """Decorator to memoize lowering methods.
1336 Ensures the decorated method is called only once, with subsequent method calls returning the
1337 object returned by the first first method call.
1339 This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` subclasses.
1340 This is to ensure that nMigen's view of representation of all values stays internally
1343 @functools.wraps(func
)
1344 def wrapper_memoized(self
, *args
, **kwargs
):
1345 if not hasattr(self
, "_ValueCastable__lowered_to"):
1346 self
.__lowered
_to
= func(self
, *args
, **kwargs
)
1347 return self
.__lowered
_to
1348 wrapper_memoized
.__memoized
= True
1349 return wrapper_memoized
1353 class Sample(Value
):
1354 """Value from the past.
1356 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1357 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1358 to the value of the expression calculated as if each signal had its reset value.
1360 def __init__(self
, expr
, clocks
, domain
, *, src_loc_at
=0):
1361 super().__init
__(src_loc_at
=1 + src_loc_at
)
1362 self
.value
= Value
.cast(expr
)
1363 self
.clocks
= int(clocks
)
1364 self
.domain
= domain
1365 if not isinstance(self
.value
, (Const
, Signal
, ClockSignal
, ResetSignal
, Initial
)):
1366 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1367 .format(self
.value
))
1369 raise ValueError("Cannot sample a value {} cycles in the future"
1370 .format(-self
.clocks
))
1371 if not (self
.domain
is None or isinstance(self
.domain
, str)):
1372 raise TypeError("Domain name must be a string or None, not {!r}"
1373 .format(self
.domain
))
1376 return self
.value
.shape()
1378 def _rhs_signals(self
):
1379 return SignalSet((self
,))
1382 return "(sample {!r} @ {}[{}])".format(
1383 self
.value
, "<default>" if self
.domain
is None else self
.domain
, self
.clocks
)
1386 def Past(expr
, clocks
=1, domain
=None):
1387 return Sample(expr
, clocks
, domain
)
1390 def Stable(expr
, clocks
=0, domain
=None):
1391 return Sample(expr
, clocks
+ 1, domain
) == Sample(expr
, clocks
, domain
)
1394 def Rose(expr
, clocks
=0, domain
=None):
1395 return ~
Sample(expr
, clocks
+ 1, domain
) & Sample(expr
, clocks
, domain
)
1398 def Fell(expr
, clocks
=0, domain
=None):
1399 return Sample(expr
, clocks
+ 1, domain
) & ~
Sample(expr
, clocks
, domain
)
1403 class Initial(Value
):
1404 """Start indicator, for model checking.
1406 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1408 def __init__(self
, *, src_loc_at
=0):
1409 super().__init
__(src_loc_at
=src_loc_at
)
1414 def _rhs_signals(self
):
1415 return SignalSet((self
,))
1421 class _StatementList(list):
1423 return "({})".format(" ".join(map(repr, self
)))
1427 def __init__(self
, *, src_loc_at
=0):
1428 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
1432 if isinstance(obj
, Iterable
):
1433 return _StatementList(list(chain
.from_iterable(map(Statement
.cast
, obj
))))
1435 if isinstance(obj
, Statement
):
1436 return _StatementList([obj
])
1438 raise TypeError("Object {!r} is not an nMigen statement".format(obj
))
1442 def Assign(lhs
, rhs
, *, src_loc_at
=0):
1443 return lhs
.__Assign
__(rhs
, src_loc_at
=src_loc_at
)
1446 class _InternalAssign(Statement
):
1447 def __init__(self
, lhs
, rhs
, *, src_loc_at
=0):
1448 super().__init
__(src_loc_at
=src_loc_at
)
1449 self
.lhs
= Value
.cast(lhs
)
1450 self
.rhs
= Value
.cast(rhs
)
1452 def _lhs_signals(self
):
1453 return self
.lhs
._lhs
_signals
()
1455 def _rhs_signals(self
):
1456 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
1459 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
1462 class UnusedProperty(UnusedMustUse
):
1466 class Property(Statement
, MustUse
):
1467 _MustUse__warning
= UnusedProperty
1469 def __init__(self
, test
, *, _check
=None, _en
=None, src_loc_at
=0):
1470 super().__init
__(src_loc_at
=src_loc_at
)
1471 self
.test
= Value
.cast(test
)
1472 self
._check
= _check
1474 if self
._check
is None:
1475 self
._check
= Signal(reset_less
=True, name
="${}$check".format(self
._kind
))
1476 self
._check
.src_loc
= self
.src_loc
1478 self
._en
= Signal(reset_less
=True, name
="${}$en".format(self
._kind
))
1479 self
._en
.src_loc
= self
.src_loc
1481 def _lhs_signals(self
):
1482 return SignalSet((self
._en
, self
._check
))
1484 def _rhs_signals(self
):
1485 return self
.test
._rhs
_signals
()
1488 return "({} {!r})".format(self
._kind
, self
.test
)
1492 class Assert(Property
):
1497 class Assume(Property
):
1502 class Cover(Property
):
1507 def Switch(test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1508 return test
.__Switch
__(cases
, src_loc
=src_loc
, src_loc_at
=src_loc_at
,
1509 case_src_locs
=case_src_locs
)
1512 class _InternalSwitch(Statement
):
1513 def __init__(self
, test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1515 super().__init
__(src_loc_at
=src_loc_at
)
1517 # Switch is a bit special in terms of location tracking because it is usually created
1518 # long after the control has left the statement that directly caused its creation.
1519 self
.src_loc
= src_loc
1520 # Switch is also a bit special in that its parts also have location information. It can't
1521 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1522 self
.case_src_locs
= {}
1524 self
.test
= Value
.cast(test
)
1525 self
.cases
= OrderedDict()
1526 for orig_keys
, stmts
in cases
.items():
1527 # Map: None -> (); key -> (key,); (key...) -> (key...)
1531 if not isinstance(keys
, tuple):
1533 # Map: 2 -> "0010"; "0010" -> "0010"
1535 key_mask
= (1 << len(self
.test
)) - 1
1537 if isinstance(key
, str):
1538 key
= "".join(key
.split()) # remove whitespace
1539 elif isinstance(key
, int):
1540 key
= format(key
& key_mask
, "b").rjust(len(self
.test
), "0")
1541 elif isinstance(key
, Enum
):
1542 key
= format(key
.value
& key_mask
, "b").rjust(len(self
.test
), "0")
1544 raise TypeError("Object {!r} cannot be used as a switch key"
1546 assert len(key
) == len(self
.test
)
1547 new_keys
= (*new_keys
, key
)
1548 if not isinstance(stmts
, Iterable
):
1550 self
.cases
[new_keys
] = Statement
.cast(stmts
)
1551 if orig_keys
in case_src_locs
:
1552 self
.case_src_locs
[new_keys
] = case_src_locs
[orig_keys
]
1554 def _lhs_signals(self
):
1555 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1559 def _rhs_signals(self
):
1560 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1562 return self
.test
._rhs
_signals
() | signals
1565 def case_repr(keys
, stmts
):
1566 stmts_repr
= " ".join(map(repr, stmts
))
1568 return "(default {})".format(stmts_repr
)
1569 elif len(keys
) == 1:
1570 return "(case {} {})".format(keys
[0], stmts_repr
)
1572 return "(case ({}) {})".format(" ".join(keys
), stmts_repr
)
1573 case_reprs
= [case_repr(keys
, stmts
) for keys
, stmts
in self
.cases
.items()]
1574 return "(switch {!r} {})".format(self
.test
, " ".join(case_reprs
))
1577 class _MappedKeyCollection(metaclass
=ABCMeta
):
1579 def _map_key(self
, key
):
1583 def _unmap_key(self
, key
):
1587 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
1588 def __init__(self
, pairs
=()):
1589 self
._storage
= OrderedDict()
1590 for key
, value
in pairs
:
1593 def __getitem__(self
, key
):
1594 key
= None if key
is None else self
._map
_key
(key
)
1595 return self
._storage
[key
]
1597 def __setitem__(self
, key
, value
):
1598 key
= None if key
is None else self
._map
_key
(key
)
1599 self
._storage
[key
] = value
1601 def __delitem__(self
, key
):
1602 key
= None if key
is None else self
._map
_key
(key
)
1603 del self
._storage
[key
]
1606 for key
in self
._storage
:
1610 yield self
._unmap
_key
(key
)
1612 def __eq__(self
, other
):
1613 if not isinstance(other
, type(self
)):
1615 if len(self
) != len(other
):
1617 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
1620 if self
._storage
[ak
] != other
._storage
[bk
]:
1625 return len(self
._storage
)
1628 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
1629 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
1633 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
1634 def __init__(self
, elements
=()):
1635 self
._storage
= OrderedDict()
1636 for elem
in elements
:
1639 def add(self
, value
):
1640 self
._storage
[self
._map
_key
(value
)] = None
1642 def update(self
, values
):
1643 for value
in values
:
1646 def discard(self
, value
):
1648 del self
._storage
[self
._map
_key
(value
)]
1650 def __contains__(self
, value
):
1651 return self
._map
_key
(value
) in self
._storage
1654 for key
in [k
for k
in self
._storage
]:
1655 yield self
._unmap
_key
(key
)
1658 return len(self
._storage
)
1661 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
1662 ", ".join(repr(x
) for x
in self
))
1666 def __init__(self
, value
):
1667 self
.value
= Value
.cast(value
)
1668 if isinstance(self
.value
, Const
):
1669 self
._hash
= hash(self
.value
.value
)
1670 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1671 self
._hash
= hash(self
.value
.duid
)
1672 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1673 self
._hash
= hash(self
.value
.domain
)
1674 elif isinstance(self
.value
, Operator
):
1675 self
._hash
= hash((self
.value
.operator
,
1676 tuple(ValueKey(o
) for o
in self
.value
.operands
)))
1677 elif isinstance(self
.value
, Slice
):
1678 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.stop
))
1679 elif isinstance(self
.value
, Part
):
1680 self
._hash
= hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
1681 self
.value
.width
, self
.value
.stride
))
1682 elif isinstance(self
.value
, Cat
):
1683 self
._hash
= hash(tuple(ValueKey(o
) for o
in self
.value
.parts
))
1684 elif isinstance(self
.value
, ArrayProxy
):
1685 self
._hash
= hash((ValueKey(self
.value
.index
),
1686 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
1687 elif isinstance(self
.value
, Sample
):
1688 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.clocks
, self
.value
.domain
))
1689 elif isinstance(self
.value
, Initial
):
1692 raise TypeError("Object {!r} cannot be used as a key in value collections"
1693 .format(self
.value
))
1698 def __eq__(self
, other
):
1699 if type(other
) is not ValueKey
:
1701 if type(self
.value
) is not type(other
.value
):
1704 if isinstance(self
.value
, Const
):
1705 return self
.value
.value
== other
.value
.value
1706 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1707 return self
.value
is other
.value
1708 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1709 return self
.value
.domain
== other
.value
.domain
1710 elif isinstance(self
.value
, Operator
):
1711 return (self
.value
.operator
== other
.value
.operator
and
1712 len(self
.value
.operands
) == len(other
.value
.operands
) and
1713 all(ValueKey(a
) == ValueKey(b
)
1714 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1715 elif isinstance(self
.value
, Slice
):
1716 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1717 self
.value
.start
== other
.value
.start
and
1718 self
.value
.stop
== other
.value
.stop
)
1719 elif isinstance(self
.value
, Part
):
1720 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1721 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1722 self
.value
.width
== other
.value
.width
and
1723 self
.value
.stride
== other
.value
.stride
)
1724 elif isinstance(self
.value
, Cat
):
1725 return all(ValueKey(a
) == ValueKey(b
)
1726 for a
, b
in zip(self
.value
.parts
, other
.value
.parts
))
1727 elif isinstance(self
.value
, ArrayProxy
):
1728 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1729 len(self
.value
.elems
) == len(other
.value
.elems
) and
1730 all(ValueKey(a
) == ValueKey(b
)
1731 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1732 other
.value
._iter
_as
_values
())))
1733 elif isinstance(self
.value
, Sample
):
1734 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1735 self
.value
.clocks
== other
.value
.clocks
and
1736 self
.value
.domain
== self
.value
.domain
)
1737 elif isinstance(self
.value
, Initial
):
1740 raise TypeError("Object {!r} cannot be used as a key in value collections"
1741 .format(self
.value
))
1743 def __lt__(self
, other
):
1744 if not isinstance(other
, ValueKey
):
1746 if type(self
.value
) != type(other
.value
):
1749 if isinstance(self
.value
, Const
):
1750 return self
.value
< other
.value
1751 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1752 return self
.value
.duid
< other
.value
.duid
1753 elif isinstance(self
.value
, Slice
):
1754 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1755 self
.value
.start
< other
.value
.start
and
1756 self
.value
.end
< other
.value
.end
)
1758 raise TypeError("Object {!r} cannot be used as a key in value collections")
1761 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1764 class ValueDict(_MappedKeyDict
):
1766 _unmap_key
= lambda self
, key
: key
.value
1769 class ValueSet(_MappedKeySet
):
1771 _unmap_key
= lambda self
, key
: key
.value
1775 def __init__(self
, signal
):
1776 self
.signal
= signal
1777 if isinstance(signal
, Signal
):
1778 self
._intern
= (0, signal
.duid
)
1779 elif type(signal
) is ClockSignal
:
1780 self
._intern
= (1, signal
.domain
)
1781 elif type(signal
) is ResetSignal
:
1782 self
._intern
= (2, signal
.domain
)
1784 raise TypeError("Object {!r} is not an nMigen signal".format(signal
))
1787 return hash(self
._intern
)
1789 def __eq__(self
, other
):
1790 if type(other
) is not SignalKey
:
1792 return self
._intern
== other
._intern
1794 def __lt__(self
, other
):
1795 if type(other
) is not SignalKey
:
1796 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal
))
1797 return self
._intern
< other
._intern
1800 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1803 class SignalDict(_MappedKeyDict
):
1804 _map_key
= SignalKey
1805 _unmap_key
= lambda self
, key
: key
.signal
1808 class SignalSet(_MappedKeySet
):
1809 _map_key
= SignalKey
1810 _unmap_key
= lambda self
, key
: key
.signal