7b1fd8f7dd4144b8391c8acf161f37796125cf4d
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",
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 __Mux__(self
, val1
, val0
):
155 return _InternalMux(self
, val1
, val0
)
157 def __Switch__(self
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
158 return _InternalSwitch(self
, cases
, src_loc
=src_loc
,
159 src_loc_at
=src_loc_at
,
160 case_src_locs
=case_src_locs
)
162 def __Assign__(self
, rhs
, *, src_loc_at
=0):
163 return _InternalAssign(self
, rhs
, src_loc_at
=src_loc_at
)
166 raise TypeError("Attempted to convert nMigen value to Python boolean")
168 def __invert__(self
):
169 return Operator("~", [self
])
171 return Operator("-", [self
])
173 def __add__(self
, other
):
174 return Operator("+", [self
, other
])
175 def __radd__(self
, other
):
176 return Operator("+", [other
, self
])
177 def __sub__(self
, other
):
178 return Operator("-", [self
, other
])
179 def __rsub__(self
, other
):
180 return Operator("-", [other
, self
])
182 def __mul__(self
, other
):
183 return Operator("*", [self
, other
])
184 def __rmul__(self
, other
):
185 return Operator("*", [other
, self
])
187 def __check_divisor(self
):
188 width
, signed
= self
.shape()
190 # Python's division semantics and Verilog's division semantics differ for negative
191 # divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
192 # completely by prohibiting such division operations.
193 raise NotImplementedError("Division by a signed value is not supported")
194 def __mod__(self
, other
):
195 other
= Value
.cast(other
)
196 other
.__check
_divisor
()
197 return Operator("%", [self
, other
])
198 def __rmod__(self
, other
):
199 self
.__check
_divisor
()
200 return Operator("%", [other
, self
])
201 def __floordiv__(self
, other
):
202 other
= Value
.cast(other
)
203 other
.__check
_divisor
()
204 return Operator("//", [self
, other
])
205 def __rfloordiv__(self
, other
):
206 self
.__check
_divisor
()
207 return Operator("//", [other
, self
])
209 def __check_shamt(self
):
210 width
, signed
= self
.shape()
212 # Neither Python nor HDLs implement shifts by negative values; prohibit any shifts
213 # by a signed value to make sure the shift amount can always be interpreted as
215 raise TypeError("Shift amount must be unsigned")
216 def __lshift__(self
, other
):
217 other
= Value
.cast(other
)
218 other
.__check
_shamt
()
219 return Operator("<<", [self
, other
])
220 def __rlshift__(self
, other
):
222 return Operator("<<", [other
, self
])
223 def __rshift__(self
, other
):
224 other
= Value
.cast(other
)
225 other
.__check
_shamt
()
226 return Operator(">>", [self
, other
])
227 def __rrshift__(self
, other
):
229 return Operator(">>", [other
, self
])
231 def __and__(self
, other
):
232 return Operator("&", [self
, other
])
233 def __rand__(self
, other
):
234 return Operator("&", [other
, self
])
235 def __xor__(self
, other
):
236 return Operator("^", [self
, other
])
237 def __rxor__(self
, other
):
238 return Operator("^", [other
, self
])
239 def __or__(self
, other
):
240 return Operator("|", [self
, other
])
241 def __ror__(self
, other
):
242 return Operator("|", [other
, self
])
244 def __eq__(self
, other
):
245 return Operator("==", [self
, other
])
246 def __ne__(self
, other
):
247 return Operator("!=", [self
, other
])
248 def __lt__(self
, other
):
249 return Operator("<", [self
, other
])
250 def __le__(self
, other
):
251 return Operator("<=", [self
, other
])
252 def __gt__(self
, other
):
253 return Operator(">", [self
, other
])
254 def __ge__(self
, other
):
255 return Operator(">=", [self
, other
])
258 width
, signed
= self
.shape()
260 return Mux(self
>= 0, self
, -self
)
265 return self
.shape().width
267 def __getitem__(self
, key
):
269 if isinstance(key
, int):
270 if key
not in range(-n
, n
):
271 raise IndexError(f
"Index {key} is out of bounds for a {n}-bit value")
274 return Slice(self
, key
, key
+ 1)
275 elif isinstance(key
, slice):
276 start
, stop
, step
= key
.indices(n
)
278 return Cat(self
[i
] for i
in range(start
, stop
, step
))
279 return Slice(self
, start
, stop
)
281 raise TypeError("Cannot index value with {}".format(repr(key
)))
283 def as_unsigned(self
):
284 """Conversion to unsigned.
289 This ``Value`` reinterpreted as a unsigned integer.
291 return Operator("u", [self
])
294 """Conversion to signed.
299 This ``Value`` reinterpreted as a signed integer.
301 return Operator("s", [self
])
304 """Conversion to boolean.
309 ``1`` if any bits are set, ``0`` otherwise.
311 return Operator("b", [self
])
314 """Check if any bits are ``1``.
319 ``1`` if any bits are set, ``0`` otherwise.
321 return Operator("r|", [self
])
324 """Check if all bits are ``1``.
329 ``1`` if all bits are set, ``0`` otherwise.
331 return Operator("r&", [self
])
334 """Compute pairwise exclusive-or of every bit.
339 ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set.
341 return Operator("r^", [self
])
343 def implies(premise
, conclusion
):
349 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
351 return ~premise | conclusion
353 def bit_select(self
, offset
, width
):
354 """Part-select with bit granularity.
356 Selects a constant width but variable offset part of a ``Value``, such that successive
357 parts overlap by all but 1 bit.
362 Index of first selected bit.
364 Number of selected bits.
369 Selected part of the ``Value``
371 offset
= Value
.cast(offset
)
372 if type(offset
) is Const
and isinstance(width
, int):
373 return self
[offset
.value
:offset
.value
+ width
]
374 return Part(self
, offset
, width
, stride
=1, src_loc_at
=1)
376 def word_select(self
, offset
, width
):
377 """Part-select with word granularity.
379 Selects a constant width but variable offset part of a ``Value``, such that successive
380 parts do not overlap.
385 Index of first selected word.
387 Number of selected bits.
392 Selected part of the ``Value``
394 offset
= Value
.cast(offset
)
395 if type(offset
) is Const
and isinstance(width
, int):
396 return self
[offset
.value
* width
:(offset
.value
+ 1) * width
]
397 return Part(self
, offset
, width
, stride
=width
, src_loc_at
=1)
399 def matches(self
, *patterns
):
402 Matches against a set of patterns, which may be integers or bit strings, recognizing
403 the same grammar as ``Case()``.
407 patterns : int or str
408 Patterns to match against.
413 ``1`` if any pattern matches the value, ``0`` otherwise.
416 for pattern
in patterns
:
417 if not isinstance(pattern
, (int, str, Enum
)):
418 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
421 if isinstance(pattern
, str) and any(bit
not in "01- \t" for bit
in pattern
):
422 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
423 "bits, and may include whitespace"
425 if (isinstance(pattern
, str) and
426 len("".join(pattern
.split())) != len(self
)):
427 raise SyntaxError("Match pattern '{}' must have the same width as match value "
429 .format(pattern
, len(self
)))
430 if isinstance(pattern
, int) and bits_for(pattern
) > len(self
):
431 warnings
.warn("Match pattern '{:b}' is wider than match value "
432 "(which has width {}); comparison will never be true"
433 .format(pattern
, len(self
)),
434 SyntaxWarning, stacklevel
=3)
436 if isinstance(pattern
, str):
437 pattern
= "".join(pattern
.split()) # remove whitespace
438 mask
= int(pattern
.replace("0", "1").replace("-", "0"), 2)
439 pattern
= int(pattern
.replace("-", "0"), 2)
440 matches
.append((self
& mask
) == pattern
)
441 elif isinstance(pattern
, int):
442 matches
.append(self
== pattern
)
443 elif isinstance(pattern
, Enum
):
444 matches
.append(self
== pattern
.value
)
449 elif len(matches
) == 1:
452 return Cat(*matches
).any()
454 def shift_left(self
, amount
):
455 """Shift left by constant amount.
465 If the amount is positive, the input shifted left. Otherwise, the input shifted right.
467 if not isinstance(amount
, int):
468 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
470 return self
.shift_right(-amount
)
471 if self
.shape().signed
:
472 return Cat(Const(0, amount
), self
).as_signed()
474 return Cat(Const(0, amount
), self
) # unsigned
476 def shift_right(self
, amount
):
477 """Shift right by constant amount.
487 If the amount is positive, the input shifted right. Otherwise, the input shifted left.
489 if not isinstance(amount
, int):
490 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
492 return self
.shift_left(-amount
)
493 if self
.shape().signed
:
494 return self
[amount
:].as_signed()
496 return self
[amount
:] # unsigned
498 def rotate_left(self
, amount
):
499 """Rotate left by constant amount.
509 If the amount is positive, the input rotated left. Otherwise, the input rotated right.
511 if not isinstance(amount
, int):
512 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
514 return Cat(self
[-amount
:], self
[:-amount
]) # meow :3
516 def rotate_right(self
, amount
):
517 """Rotate right by constant amount.
527 If the amount is positive, the input rotated right. Otherwise, the input rotated right.
529 if not isinstance(amount
, int):
530 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
532 return Cat(self
[amount
:], self
[:amount
])
540 Value to be assigned.
545 Assignment statement that can be used in combinatorial or synchronous context.
547 return Assign(self
, value
, src_loc_at
=1)
551 """Bit width and signedness of a value.
560 >>> Signal(8).shape()
561 Shape(width=8, signed=False)
562 >>> Const(0xaa).shape()
563 Shape(width=8, signed=False)
567 def _lhs_signals(self
):
568 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
571 def _rhs_signals(self
):
575 raise TypeError("Value {!r} cannot be evaluated as constant".format(self
))
582 """A constant, literal integer value.
587 shape : int or tuple or None
588 Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
589 in this constant and whether it is signed (can represent negative values).
590 ``shape`` defaults to the minimum possible width and signedness of ``value``.
600 def normalize(value
, shape
):
601 width
, signed
= shape
602 mask
= (1 << width
) - 1
604 if signed
and value
>> (width
- 1):
608 def __init__(self
, value
, shape
=None, *, src_loc_at
=0):
609 # We deliberately do not call Value.__init__ here.
610 self
.value
= int(value
)
612 shape
= Shape(bits_for(self
.value
), signed
=self
.value
< 0)
613 elif isinstance(shape
, int):
614 shape
= Shape(shape
, signed
=self
.value
< 0)
616 shape
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
617 self
.width
, self
.signed
= shape
618 self
.value
= self
.normalize(self
.value
, shape
)
621 return Shape(self
.width
, self
.signed
)
623 def _rhs_signals(self
):
630 return "(const {}'{}d{})".format(self
.width
, "s" if self
.signed
else "", self
.value
)
633 C
= Const
# shorthand
636 class AnyValue(Value
, DUID
):
637 def __init__(self
, shape
, *, src_loc_at
=0):
638 super().__init
__(src_loc_at
=src_loc_at
)
639 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
640 if not isinstance(self
.width
, int) or self
.width
< 0:
641 raise TypeError("Width must be a non-negative integer, not {!r}"
645 return Shape(self
.width
, self
.signed
)
647 def _rhs_signals(self
):
652 class AnyConst(AnyValue
):
654 return "(anyconst {}'{})".format(self
.width
, "s" if self
.signed
else "")
658 class AnySeq(AnyValue
):
660 return "(anyseq {}'{})".format(self
.width
, "s" if self
.signed
else "")
664 class Operator(Value
):
665 def __init__(self
, operator
, operands
, *, src_loc_at
=0):
666 super().__init
__(src_loc_at
=1 + src_loc_at
)
667 self
.operator
= operator
668 self
.operands
= [Value
.cast(op
) for op
in operands
]
671 def _bitwise_binary_shape(a_shape
, b_shape
):
672 a_bits
, a_sign
= a_shape
673 b_bits
, b_sign
= b_shape
674 if not a_sign
and not b_sign
:
675 # both operands unsigned
676 return Shape(max(a_bits
, b_bits
), False)
677 elif a_sign
and b_sign
:
678 # both operands signed
679 return Shape(max(a_bits
, b_bits
), True)
680 elif not a_sign
and b_sign
:
681 # first operand unsigned (add sign bit), second operand signed
682 return Shape(max(a_bits
+ 1, b_bits
), True)
684 # first signed, second operand unsigned (add sign bit)
685 return Shape(max(a_bits
, b_bits
+ 1), True)
687 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
688 if len(op_shapes
) == 1:
689 (a_width
, a_signed
), = op_shapes
690 if self
.operator
in ("+", "~"):
691 return Shape(a_width
, a_signed
)
692 if self
.operator
== "-":
693 return Shape(a_width
+ 1, True)
694 if self
.operator
in ("b", "r|", "r&", "r^"):
695 return Shape(1, False)
696 if self
.operator
== "u":
697 return Shape(a_width
, False)
698 if self
.operator
== "s":
699 return Shape(a_width
, True)
700 elif len(op_shapes
) == 2:
701 (a_width
, a_signed
), (b_width
, b_signed
) = op_shapes
702 if self
.operator
in ("+", "-"):
703 width
, signed
= _bitwise_binary_shape(*op_shapes
)
704 return Shape(width
+ 1, signed
)
705 if self
.operator
== "*":
706 return Shape(a_width
+ b_width
, a_signed
or b_signed
)
707 if self
.operator
in ("//", "%"):
709 return Shape(a_width
, a_signed
)
710 if self
.operator
in ("<", "<=", "==", "!=", ">", ">="):
711 return Shape(1, False)
712 if self
.operator
in ("&", "^", "|"):
713 return _bitwise_binary_shape(*op_shapes
)
714 if self
.operator
== "<<":
716 return Shape(a_width
+ 2 ** b_width
- 1, a_signed
)
717 if self
.operator
== ">>":
719 return Shape(a_width
, a_signed
)
720 elif len(op_shapes
) == 3:
721 if self
.operator
== "m":
722 s_shape
, a_shape
, b_shape
= op_shapes
723 return _bitwise_binary_shape(a_shape
, b_shape
)
724 raise NotImplementedError("Operator {}/{} not implemented"
725 .format(self
.operator
, len(op_shapes
))) # :nocov:
727 def _rhs_signals(self
):
728 return union(op
._rhs
_signals
() for op
in self
.operands
)
731 return "({} {})".format(self
.operator
, " ".join(map(repr, self
.operands
)))
734 def Mux(sel
, val1
, val0
):
735 if isinstance(sel
, bool): # one instance where Mux is passed an actual bool
736 sel
= Value
.cast(sel
)
737 return sel
.__Mux
__(val1
, val0
)
740 def _InternalMux(sel
, val1
, val0
):
741 """Choose between two values.
754 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
756 sel
= Value
.cast(sel
)
759 return Operator("m", [sel
, val1
, val0
])
764 def __init__(self
, value
, start
, stop
, *, src_loc_at
=0):
765 if not isinstance(start
, int):
766 raise TypeError("Slice start must be an integer, not {!r}".format(start
))
767 if not isinstance(stop
, int):
768 raise TypeError("Slice stop must be an integer, not {!r}".format(stop
))
771 if start
not in range(-(n
+1), n
+1):
772 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
775 if stop
not in range(-(n
+1), n
+1):
776 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop
, n
))
780 raise IndexError("Slice start {} must be less than slice stop {}".format(start
, stop
))
782 super().__init
__(src_loc_at
=src_loc_at
)
783 self
.value
= Value
.cast(value
)
784 self
.start
= int(start
)
785 self
.stop
= int(stop
)
788 return Shape(self
.stop
- self
.start
)
790 def _lhs_signals(self
):
791 return self
.value
._lhs
_signals
()
793 def _rhs_signals(self
):
794 return self
.value
._rhs
_signals
()
797 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.stop
)
802 def __init__(self
, value
, offset
, width
, stride
=1, *, src_loc_at
=0):
803 if not isinstance(width
, int) or width
< 0:
804 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width
))
805 if not isinstance(stride
, int) or stride
<= 0:
806 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride
))
808 super().__init
__(src_loc_at
=src_loc_at
)
810 self
.offset
= Value
.cast(offset
)
815 return Shape(self
.width
)
817 def _lhs_signals(self
):
818 return self
.value
._lhs
_signals
()
820 def _rhs_signals(self
):
821 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
824 return "(part {} {} {} {})".format(repr(self
.value
), repr(self
.offset
),
825 self
.width
, self
.stride
)
830 """Concatenate values.
832 Form a compound ``Value`` from several smaller ones by concatenation.
833 The first argument occupies the lower bits of the result.
834 The return value can be used on either side of an assignment, that
835 is, the concatenated value can be used as an argument on the RHS or
836 as a target on the LHS. If it is used on the LHS, it must solely
837 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
838 meeting these properties. The bit length of the return value is the sum of
839 the bit lengths of the arguments::
841 len(Cat(args)) == sum(len(arg) for arg in args)
845 *args : Values or iterables of Values, inout
846 ``Value`` s to be concatenated.
851 Resulting ``Value`` obtained by concatentation.
853 def __init__(self
, *args
, src_loc_at
=0):
854 super().__init
__(src_loc_at
=src_loc_at
)
855 self
.parts
= [Value
.cast(v
) for v
in flatten(args
)]
858 return Shape(sum(len(part
) for part
in self
.parts
))
860 def _lhs_signals(self
):
861 return union((part
._lhs
_signals
() for part
in self
.parts
), start
=SignalSet())
863 def _rhs_signals(self
):
864 return union((part
._rhs
_signals
() for part
in self
.parts
), start
=SignalSet())
868 for part
in reversed(self
.parts
):
870 value |
= part
._as
_const
()
874 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
881 An input value is replicated (repeated) several times
882 to be used on the RHS of assignments::
884 len(Repl(s, n)) == len(s) * n
889 Input value to be replicated.
891 Number of replications.
898 def __init__(self
, value
, count
, *, src_loc_at
=0):
899 if not isinstance(count
, int) or count
< 0:
900 raise TypeError("Replication count must be a non-negative integer, not {!r}"
903 super().__init
__(src_loc_at
=src_loc_at
)
904 self
.value
= Value
.cast(value
)
908 return Shape(len(self
.value
) * self
.count
)
910 def _rhs_signals(self
):
911 return self
.value
._rhs
_signals
()
914 return "(repl {!r} {})".format(self
.value
, self
.count
)
918 class Signal(Value
, DUID
):
919 """A varying integer value.
923 shape : ``Shape``-castable object or None
924 Specification for the number of bits in this ``Signal`` and its signedness (whether it
925 can represent negative values). See ``Shape.cast`` for details.
926 If not specified, ``shape`` defaults to 1-bit and non-signed.
928 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
929 name this ``Signal`` is assigned to.
930 reset : int or integral Enum
931 Reset (synchronous) or default (combinatorial) value.
932 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
933 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
934 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
935 assumes its ``reset`` value. Defaults to 0.
937 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
938 The ``reset`` value is only used as a combinatorial default or as the initial value.
939 Defaults to ``False``.
941 Dictionary of synthesis attributes.
942 decoder : function or Enum
943 A function converting integer signal values to human-readable strings (e.g. FSM state
944 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
945 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
959 def __init__(self
, shape
=None, *, name
=None, reset
=0, reset_less
=False,
960 attrs
=None, decoder
=None, src_loc_at
=0):
961 super().__init
__(src_loc_at
=src_loc_at
)
963 if name
is not None and not isinstance(name
, str):
964 raise TypeError("Name must be a string, not {!r}".format(name
))
965 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$signal")
969 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
971 if isinstance(reset
, Enum
):
973 if not isinstance(reset
, int):
974 raise TypeError("Reset value has to be an int or an integral Enum")
976 reset_width
= bits_for(reset
, self
.signed
)
977 if reset
!= 0 and reset_width
> self
.width
:
978 warnings
.warn("Reset value {!r} requires {} bits to represent, but the signal "
980 .format(reset
, reset_width
, self
.width
),
981 SyntaxWarning, stacklevel
=2 + src_loc_at
)
984 self
.reset_less
= bool(reset_less
)
986 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
988 if decoder
is None and isinstance(shape
, type) and issubclass(shape
, Enum
):
990 if isinstance(decoder
, type) and issubclass(decoder
, Enum
):
991 def enum_decoder(value
):
993 return "{0.name:}/{0.value:}".format(decoder(value
))
996 self
.decoder
= enum_decoder
997 self
._enum
_class
= decoder
999 self
.decoder
= decoder
1000 self
._enum
_class
= None
1002 # Not a @classmethod because nmigen.compat requires it.
1004 def like(other
, *, name
=None, name_suffix
=None, src_loc_at
=0, **kwargs
):
1005 """Create Signal based on another.
1010 Object to base this Signal on.
1012 if name
is not None:
1013 new_name
= str(name
)
1014 elif name_suffix
is not None:
1015 new_name
= other
.name
+ str(name_suffix
)
1017 new_name
= tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$like")
1018 kw
= dict(shape
=Value
.cast(other
).shape(), name
=new_name
)
1019 if isinstance(other
, Signal
):
1020 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
1021 attrs
=other
.attrs
, decoder
=other
.decoder
)
1023 return Signal(**kw
, src_loc_at
=1 + src_loc_at
)
1026 return Shape(self
.width
, self
.signed
)
1028 def _lhs_signals(self
):
1029 return SignalSet((self
,))
1031 def _rhs_signals(self
):
1032 return SignalSet((self
,))
1035 return "(sig {})".format(self
.name
)
1039 class ClockSignal(Value
):
1040 """Clock signal for a clock domain.
1042 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
1043 All of these signals ultimately refer to the same signal, but they can be manipulated
1044 independently of the clock domain, even before the clock domain is created.
1049 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
1051 def __init__(self
, domain
="sync", *, src_loc_at
=0):
1052 super().__init
__(src_loc_at
=src_loc_at
)
1053 if not isinstance(domain
, str):
1054 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1055 if domain
== "comb":
1056 raise ValueError("Domain '{}' does not have a clock".format(domain
))
1057 self
.domain
= domain
1062 def _lhs_signals(self
):
1063 return SignalSet((self
,))
1065 def _rhs_signals(self
):
1066 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
1069 return "(clk {})".format(self
.domain
)
1073 class ResetSignal(Value
):
1074 """Reset signal for a clock domain.
1076 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
1077 All of these signals ultimately refer to the same signal, but they can be manipulated
1078 independently of the clock domain, even before the clock domain is created.
1083 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
1084 allow_reset_less : bool
1085 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
1087 def __init__(self
, domain
="sync", allow_reset_less
=False, *, src_loc_at
=0):
1088 super().__init
__(src_loc_at
=src_loc_at
)
1089 if not isinstance(domain
, str):
1090 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1091 if domain
== "comb":
1092 raise ValueError("Domain '{}' does not have a reset".format(domain
))
1093 self
.domain
= domain
1094 self
.allow_reset_less
= allow_reset_less
1099 def _lhs_signals(self
):
1100 return SignalSet((self
,))
1102 def _rhs_signals(self
):
1103 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
1106 return "(rst {})".format(self
.domain
)
1109 class Array(MutableSequence
):
1110 """Addressable multiplexer.
1112 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
1115 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
1116 assignments, provided that all elements of the array are values. The array proxy also supports
1117 attribute access and further indexing, each returning another array proxy; this means that
1118 the results of indexing into arrays, arrays of records, and arrays of arrays can all
1119 be used as first-class values.
1121 It is an error to change an array or any of its elements after an array proxy was created.
1122 Changing the array directly will raise an exception. However, it is not possible to detect
1123 the elements being modified; if an element's attribute or element is modified after the proxy
1124 for it has been created, the proxy will refer to stale data.
1131 gpios = Array(Signal() for _ in range(10))
1133 m.d.sync += gpios[bus.addr].eq(bus.w_data)
1135 m.d.sync += bus.r_data.eq(gpios[bus.addr])
1137 Multidimensional array::
1139 mult = Array(Array(x * y for y in range(10)) for x in range(10))
1140 a = Signal.range(10)
1141 b = Signal.range(10)
1143 m.d.comb += r.eq(mult[a][b])
1151 buses = Array(Record(layout) for busno in range(4))
1152 master = Record(layout)
1154 buses[sel].r_en.eq(master.r_en),
1155 master.r_data.eq(buses[sel].r_data),
1158 def __init__(self
, iterable
=()):
1159 self
._inner
= list(iterable
)
1160 self
._proxy
_at
= None
1161 self
._mutable
= True
1163 def __getitem__(self
, index
):
1164 if isinstance(index
, Value
):
1166 self
._proxy
_at
= tracer
.get_src_loc()
1167 self
._mutable
= False
1168 return ArrayProxy(self
, index
)
1170 return self
._inner
[index
]
1173 return len(self
._inner
)
1175 def _check_mutability(self
):
1176 if not self
._mutable
:
1177 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1178 "at {}:{}".format(*self
._proxy
_at
))
1180 def __setitem__(self
, index
, value
):
1181 self
._check
_mutability
()
1182 self
._inner
[index
] = value
1184 def __delitem__(self
, index
):
1185 self
._check
_mutability
()
1186 del self
._inner
[index
]
1188 def insert(self
, index
, value
):
1189 self
._check
_mutability
()
1190 self
._inner
.insert(index
, value
)
1193 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
1194 ", ".join(map(repr, self
._inner
)))
1198 class ArrayProxy(Value
):
1199 def __init__(self
, elems
, index
, *, src_loc_at
=0):
1200 super().__init
__(src_loc_at
=1 + src_loc_at
)
1202 self
.index
= Value
.cast(index
)
1204 def __getattr__(self
, attr
):
1205 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
1207 def __getitem__(self
, index
):
1208 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
1210 def _iter_as_values(self
):
1211 return (Value
.cast(elem
) for elem
in self
.elems
)
1214 unsigned_width
= signed_width
= 0
1215 has_unsigned
= has_signed
= False
1216 for elem_width
, elem_signed
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
1219 signed_width
= max(signed_width
, elem_width
)
1222 unsigned_width
= max(unsigned_width
, elem_width
)
1223 # The shape of the proxy must be such that it preserves the mathematical value of the array
1224 # elements. I.e., shape-wise, an array proxy must be identical to an equivalent mux tree.
1225 # To ensure this holds, if the array contains both signed and unsigned values, make sure
1226 # that every unsigned value is zero-extended by at least one bit.
1227 if has_signed
and has_unsigned
and unsigned_width
>= signed_width
:
1228 # Array contains both signed and unsigned values, and at least one of the unsigned
1229 # values won't be zero-extended otherwise.
1230 return signed(unsigned_width
+ 1)
1232 # Array contains values of the same signedness, or else all of the unsigned values
1233 # are zero-extended.
1234 return Shape(max(unsigned_width
, signed_width
), has_signed
)
1236 def _lhs_signals(self
):
1237 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()),
1241 def _rhs_signals(self
):
1242 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()),
1244 return self
.index
._rhs
_signals
() | signals
1247 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
1250 # TODO(nmigen-0.4): remove
1251 class UserValue(Value
):
1252 """Value with custom lowering.
1254 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1255 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1256 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1257 value when required.
1259 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1260 nMigen's view of representation of all values stays internally consistent. If the class
1261 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1262 it is not mutated in a way that changes its representation.
1264 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1265 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1266 * Querying the shape using ``.shape()`` or ``len()``;
1267 * Creating a similarly shaped signal using ``Signal.like``;
1268 * Indexing or iterating through individual bits;
1269 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1271 @deprecated("instead of `UserValue`, use `ValueCastable`", stacklevel
=3)
1272 def __init__(self
, *, src_loc_at
=0):
1273 super().__init
__(src_loc_at
=1 + src_loc_at
)
1274 self
.__lowered
= None
1278 """Conversion to a concrete representation."""
1281 def _lazy_lower(self
):
1282 if self
.__lowered
is None:
1283 lowered
= self
.lower()
1284 if isinstance(lowered
, UserValue
):
1285 lowered
= lowered
._lazy
_lower
()
1286 self
.__lowered
= Value
.cast(lowered
)
1287 return self
.__lowered
1290 return self
._lazy
_lower
().shape()
1292 def _lhs_signals(self
):
1293 return self
._lazy
_lower
()._lhs
_signals
()
1295 def _rhs_signals(self
):
1296 return self
._lazy
_lower
()._rhs
_signals
()
1299 class ValueCastable
:
1300 """Base class for classes which can be cast to Values.
1302 A ``ValueCastable`` can be cast to ``Value``, meaning its precise representation does not have
1303 to be immediately known. This is useful in certain metaprogramming scenarios. Instead of
1304 providing fixed semantics upfront, it is kept abstract for as long as possible, only being
1305 cast to a concrete nMigen value when required.
1307 Note that it is necessary to ensure that nMigen's view of representation of all values stays
1308 internally consistent. The class deriving from ``ValueCastable`` must decorate the ``as_value``
1309 method with the ``lowermethod`` decorator, which ensures that all calls to ``as_value`` return
1310 the same ``Value`` representation. If the class deriving from ``ValueCastable`` is mutable,
1311 it is up to the user to ensure that it is not mutated in a way that changes its representation
1312 after the first call to ``as_value``.
1314 def __new__(cls
, *args
, **kwargs
):
1315 self
= super().__new
__(cls
)
1316 if not hasattr(self
, "as_value"):
1317 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must override "
1318 "the `as_value` method")
1320 if not hasattr(self
.as_value
, "_ValueCastable__memoized"):
1321 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must decorate "
1322 "the `as_value` method with the `ValueCastable.lowermethod` decorator")
1326 def lowermethod(func
):
1327 """Decorator to memoize lowering methods.
1329 Ensures the decorated method is called only once, with subsequent method calls returning the
1330 object returned by the first first method call.
1332 This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` subclasses.
1333 This is to ensure that nMigen's view of representation of all values stays internally
1336 @functools.wraps(func
)
1337 def wrapper_memoized(self
, *args
, **kwargs
):
1338 if not hasattr(self
, "_ValueCastable__lowered_to"):
1339 self
.__lowered
_to
= func(self
, *args
, **kwargs
)
1340 return self
.__lowered
_to
1341 wrapper_memoized
.__memoized
= True
1342 return wrapper_memoized
1346 class Sample(Value
):
1347 """Value from the past.
1349 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1350 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1351 to the value of the expression calculated as if each signal had its reset value.
1353 def __init__(self
, expr
, clocks
, domain
, *, src_loc_at
=0):
1354 super().__init
__(src_loc_at
=1 + src_loc_at
)
1355 self
.value
= Value
.cast(expr
)
1356 self
.clocks
= int(clocks
)
1357 self
.domain
= domain
1358 if not isinstance(self
.value
, (Const
, Signal
, ClockSignal
, ResetSignal
, Initial
)):
1359 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1360 .format(self
.value
))
1362 raise ValueError("Cannot sample a value {} cycles in the future"
1363 .format(-self
.clocks
))
1364 if not (self
.domain
is None or isinstance(self
.domain
, str)):
1365 raise TypeError("Domain name must be a string or None, not {!r}"
1366 .format(self
.domain
))
1369 return self
.value
.shape()
1371 def _rhs_signals(self
):
1372 return SignalSet((self
,))
1375 return "(sample {!r} @ {}[{}])".format(
1376 self
.value
, "<default>" if self
.domain
is None else self
.domain
, self
.clocks
)
1379 def Past(expr
, clocks
=1, domain
=None):
1380 return Sample(expr
, clocks
, domain
)
1383 def Stable(expr
, clocks
=0, domain
=None):
1384 return Sample(expr
, clocks
+ 1, domain
) == Sample(expr
, clocks
, domain
)
1387 def Rose(expr
, clocks
=0, domain
=None):
1388 return ~
Sample(expr
, clocks
+ 1, domain
) & Sample(expr
, clocks
, domain
)
1391 def Fell(expr
, clocks
=0, domain
=None):
1392 return Sample(expr
, clocks
+ 1, domain
) & ~
Sample(expr
, clocks
, domain
)
1396 class Initial(Value
):
1397 """Start indicator, for model checking.
1399 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1401 def __init__(self
, *, src_loc_at
=0):
1402 super().__init
__(src_loc_at
=src_loc_at
)
1407 def _rhs_signals(self
):
1408 return SignalSet((self
,))
1414 class _StatementList(list):
1416 return "({})".format(" ".join(map(repr, self
)))
1420 def __init__(self
, *, src_loc_at
=0):
1421 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
1425 if isinstance(obj
, Iterable
):
1426 return _StatementList(list(chain
.from_iterable(map(Statement
.cast
, obj
))))
1428 if isinstance(obj
, Statement
):
1429 return _StatementList([obj
])
1431 raise TypeError("Object {!r} is not an nMigen statement".format(obj
))
1435 def Assign(lhs
, rhs
, *, src_loc_at
=0):
1436 return lhs
.__Assign
__(rhs
, src_loc_at
=src_loc_at
)
1439 class _InternalAssign(Statement
):
1440 def __init__(self
, lhs
, rhs
, *, src_loc_at
=0):
1441 super().__init
__(src_loc_at
=src_loc_at
)
1442 self
.lhs
= Value
.cast(lhs
)
1443 self
.rhs
= Value
.cast(rhs
)
1445 def _lhs_signals(self
):
1446 return self
.lhs
._lhs
_signals
()
1448 def _rhs_signals(self
):
1449 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
1452 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
1455 class UnusedProperty(UnusedMustUse
):
1459 class Property(Statement
, MustUse
):
1460 _MustUse__warning
= UnusedProperty
1462 def __init__(self
, test
, *, _check
=None, _en
=None, src_loc_at
=0):
1463 super().__init
__(src_loc_at
=src_loc_at
)
1464 self
.test
= Value
.cast(test
)
1465 self
._check
= _check
1467 if self
._check
is None:
1468 self
._check
= Signal(reset_less
=True, name
="${}$check".format(self
._kind
))
1469 self
._check
.src_loc
= self
.src_loc
1471 self
._en
= Signal(reset_less
=True, name
="${}$en".format(self
._kind
))
1472 self
._en
.src_loc
= self
.src_loc
1474 def _lhs_signals(self
):
1475 return SignalSet((self
._en
, self
._check
))
1477 def _rhs_signals(self
):
1478 return self
.test
._rhs
_signals
()
1481 return "({} {!r})".format(self
._kind
, self
.test
)
1485 class Assert(Property
):
1490 class Assume(Property
):
1495 class Cover(Property
):
1500 def Switch(test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1501 return test
.__Switch
__(cases
, src_loc
=src_loc
, src_loc_at
=src_loc_at
,
1502 case_src_locs
=case_src_locs
)
1505 class _InternalSwitch(Statement
):
1506 def __init__(self
, test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1508 super().__init
__(src_loc_at
=src_loc_at
)
1510 # Switch is a bit special in terms of location tracking because it is usually created
1511 # long after the control has left the statement that directly caused its creation.
1512 self
.src_loc
= src_loc
1513 # Switch is also a bit special in that its parts also have location information. It can't
1514 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1515 self
.case_src_locs
= {}
1517 self
.test
= Value
.cast(test
)
1518 self
.cases
= OrderedDict()
1519 for orig_keys
, stmts
in cases
.items():
1520 # Map: None -> (); key -> (key,); (key...) -> (key...)
1524 if not isinstance(keys
, tuple):
1526 # Map: 2 -> "0010"; "0010" -> "0010"
1528 key_mask
= (1 << len(self
.test
)) - 1
1530 if isinstance(key
, str):
1531 key
= "".join(key
.split()) # remove whitespace
1532 elif isinstance(key
, int):
1533 key
= format(key
& key_mask
, "b").rjust(len(self
.test
), "0")
1534 elif isinstance(key
, Enum
):
1535 key
= format(key
.value
& key_mask
, "b").rjust(len(self
.test
), "0")
1537 raise TypeError("Object {!r} cannot be used as a switch key"
1539 assert len(key
) == len(self
.test
)
1540 new_keys
= (*new_keys
, key
)
1541 if not isinstance(stmts
, Iterable
):
1543 self
.cases
[new_keys
] = Statement
.cast(stmts
)
1544 if orig_keys
in case_src_locs
:
1545 self
.case_src_locs
[new_keys
] = case_src_locs
[orig_keys
]
1547 def _lhs_signals(self
):
1548 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1552 def _rhs_signals(self
):
1553 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1555 return self
.test
._rhs
_signals
() | signals
1558 def case_repr(keys
, stmts
):
1559 stmts_repr
= " ".join(map(repr, stmts
))
1561 return "(default {})".format(stmts_repr
)
1562 elif len(keys
) == 1:
1563 return "(case {} {})".format(keys
[0], stmts_repr
)
1565 return "(case ({}) {})".format(" ".join(keys
), stmts_repr
)
1566 case_reprs
= [case_repr(keys
, stmts
) for keys
, stmts
in self
.cases
.items()]
1567 return "(switch {!r} {})".format(self
.test
, " ".join(case_reprs
))
1570 class _MappedKeyCollection(metaclass
=ABCMeta
):
1572 def _map_key(self
, key
):
1576 def _unmap_key(self
, key
):
1580 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
1581 def __init__(self
, pairs
=()):
1582 self
._storage
= OrderedDict()
1583 for key
, value
in pairs
:
1586 def __getitem__(self
, key
):
1587 key
= None if key
is None else self
._map
_key
(key
)
1588 return self
._storage
[key
]
1590 def __setitem__(self
, key
, value
):
1591 key
= None if key
is None else self
._map
_key
(key
)
1592 self
._storage
[key
] = value
1594 def __delitem__(self
, key
):
1595 key
= None if key
is None else self
._map
_key
(key
)
1596 del self
._storage
[key
]
1599 for key
in self
._storage
:
1603 yield self
._unmap
_key
(key
)
1605 def __eq__(self
, other
):
1606 if not isinstance(other
, type(self
)):
1608 if len(self
) != len(other
):
1610 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
1613 if self
._storage
[ak
] != other
._storage
[bk
]:
1618 return len(self
._storage
)
1621 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
1622 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
1626 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
1627 def __init__(self
, elements
=()):
1628 self
._storage
= OrderedDict()
1629 for elem
in elements
:
1632 def add(self
, value
):
1633 self
._storage
[self
._map
_key
(value
)] = None
1635 def update(self
, values
):
1636 for value
in values
:
1639 def discard(self
, value
):
1641 del self
._storage
[self
._map
_key
(value
)]
1643 def __contains__(self
, value
):
1644 return self
._map
_key
(value
) in self
._storage
1647 for key
in [k
for k
in self
._storage
]:
1648 yield self
._unmap
_key
(key
)
1651 return len(self
._storage
)
1654 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
1655 ", ".join(repr(x
) for x
in self
))
1659 def __init__(self
, value
):
1660 self
.value
= Value
.cast(value
)
1661 if isinstance(self
.value
, Const
):
1662 self
._hash
= hash(self
.value
.value
)
1663 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1664 self
._hash
= hash(self
.value
.duid
)
1665 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1666 self
._hash
= hash(self
.value
.domain
)
1667 elif isinstance(self
.value
, Operator
):
1668 self
._hash
= hash((self
.value
.operator
,
1669 tuple(ValueKey(o
) for o
in self
.value
.operands
)))
1670 elif isinstance(self
.value
, Slice
):
1671 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.stop
))
1672 elif isinstance(self
.value
, Part
):
1673 self
._hash
= hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
1674 self
.value
.width
, self
.value
.stride
))
1675 elif isinstance(self
.value
, Cat
):
1676 self
._hash
= hash(tuple(ValueKey(o
) for o
in self
.value
.parts
))
1677 elif isinstance(self
.value
, ArrayProxy
):
1678 self
._hash
= hash((ValueKey(self
.value
.index
),
1679 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
1680 elif isinstance(self
.value
, Sample
):
1681 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.clocks
, self
.value
.domain
))
1682 elif isinstance(self
.value
, Initial
):
1685 raise TypeError("Object {!r} cannot be used as a key in value collections"
1686 .format(self
.value
))
1691 def __eq__(self
, other
):
1692 if type(other
) is not ValueKey
:
1694 if type(self
.value
) is not type(other
.value
):
1697 if isinstance(self
.value
, Const
):
1698 return self
.value
.value
== other
.value
.value
1699 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1700 return self
.value
is other
.value
1701 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1702 return self
.value
.domain
== other
.value
.domain
1703 elif isinstance(self
.value
, Operator
):
1704 return (self
.value
.operator
== other
.value
.operator
and
1705 len(self
.value
.operands
) == len(other
.value
.operands
) and
1706 all(ValueKey(a
) == ValueKey(b
)
1707 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1708 elif isinstance(self
.value
, Slice
):
1709 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1710 self
.value
.start
== other
.value
.start
and
1711 self
.value
.stop
== other
.value
.stop
)
1712 elif isinstance(self
.value
, Part
):
1713 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1714 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1715 self
.value
.width
== other
.value
.width
and
1716 self
.value
.stride
== other
.value
.stride
)
1717 elif isinstance(self
.value
, Cat
):
1718 return all(ValueKey(a
) == ValueKey(b
)
1719 for a
, b
in zip(self
.value
.parts
, other
.value
.parts
))
1720 elif isinstance(self
.value
, ArrayProxy
):
1721 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1722 len(self
.value
.elems
) == len(other
.value
.elems
) and
1723 all(ValueKey(a
) == ValueKey(b
)
1724 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1725 other
.value
._iter
_as
_values
())))
1726 elif isinstance(self
.value
, Sample
):
1727 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1728 self
.value
.clocks
== other
.value
.clocks
and
1729 self
.value
.domain
== self
.value
.domain
)
1730 elif isinstance(self
.value
, Initial
):
1733 raise TypeError("Object {!r} cannot be used as a key in value collections"
1734 .format(self
.value
))
1736 def __lt__(self
, other
):
1737 if not isinstance(other
, ValueKey
):
1739 if type(self
.value
) != type(other
.value
):
1742 if isinstance(self
.value
, Const
):
1743 return self
.value
< other
.value
1744 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1745 return self
.value
.duid
< other
.value
.duid
1746 elif isinstance(self
.value
, Slice
):
1747 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1748 self
.value
.start
< other
.value
.start
and
1749 self
.value
.end
< other
.value
.end
)
1751 raise TypeError("Object {!r} cannot be used as a key in value collections")
1754 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1757 class ValueDict(_MappedKeyDict
):
1759 _unmap_key
= lambda self
, key
: key
.value
1762 class ValueSet(_MappedKeySet
):
1764 _unmap_key
= lambda self
, key
: key
.value
1768 def __init__(self
, signal
):
1769 self
.signal
= signal
1770 if isinstance(signal
, Signal
):
1771 self
._intern
= (0, signal
.duid
)
1772 elif type(signal
) is ClockSignal
:
1773 self
._intern
= (1, signal
.domain
)
1774 elif type(signal
) is ResetSignal
:
1775 self
._intern
= (2, signal
.domain
)
1777 raise TypeError("Object {!r} is not an nMigen signal".format(signal
))
1780 return hash(self
._intern
)
1782 def __eq__(self
, other
):
1783 if type(other
) is not SignalKey
:
1785 return self
._intern
== other
._intern
1787 def __lt__(self
, other
):
1788 if type(other
) is not SignalKey
:
1789 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal
))
1790 return self
._intern
< other
._intern
1793 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1796 class SignalDict(_MappedKeyDict
):
1797 _map_key
= SignalKey
1798 _unmap_key
= lambda self
, key
: key
.signal
1801 class SignalSet(_MappedKeySet
):
1802 _map_key
= SignalKey
1803 _unmap_key
= lambda self
, key
: key
.signal