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", "_InternalCat",
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 __Cat__(self
, *args
, src_loc_at
=0):
158 args
= [self
] + list(args
)
159 return _InternalCat(*args
, src_loc_at
=src_loc_at
)
161 def __Mux__(self
, val1
, val0
):
162 return _InternalMux(self
, val1
, val0
)
164 def __Switch__(self
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
165 return _InternalSwitch(self
, cases
, src_loc
=src_loc
,
166 src_loc_at
=src_loc_at
,
167 case_src_locs
=case_src_locs
)
169 def __Assign__(self
, rhs
, *, src_loc_at
=0):
170 return _InternalAssign(self
, rhs
, src_loc_at
=src_loc_at
)
173 raise TypeError("Attempted to convert nMigen value to Python boolean")
175 def __invert__(self
):
176 return Operator("~", [self
])
178 return Operator("-", [self
])
180 def __add__(self
, other
):
181 return Operator("+", [self
, other
])
182 def __radd__(self
, other
):
183 return Operator("+", [other
, self
])
184 def __sub__(self
, other
):
185 return Operator("-", [self
, other
])
186 def __rsub__(self
, other
):
187 return Operator("-", [other
, self
])
189 def __mul__(self
, other
):
190 return Operator("*", [self
, other
])
191 def __rmul__(self
, other
):
192 return Operator("*", [other
, self
])
194 def __check_divisor(self
):
195 width
, signed
= self
.shape()
197 # Python's division semantics and Verilog's division semantics differ for negative
198 # divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
199 # completely by prohibiting such division operations.
200 raise NotImplementedError("Division by a signed value is not supported")
201 def __mod__(self
, other
):
202 other
= Value
.cast(other
)
203 other
.__check
_divisor
()
204 return Operator("%", [self
, other
])
205 def __rmod__(self
, other
):
206 self
.__check
_divisor
()
207 return Operator("%", [other
, self
])
208 def __floordiv__(self
, other
):
209 other
= Value
.cast(other
)
210 other
.__check
_divisor
()
211 return Operator("//", [self
, other
])
212 def __rfloordiv__(self
, other
):
213 self
.__check
_divisor
()
214 return Operator("//", [other
, self
])
216 def __check_shamt(self
):
217 width
, signed
= self
.shape()
219 # Neither Python nor HDLs implement shifts by negative values; prohibit any shifts
220 # by a signed value to make sure the shift amount can always be interpreted as
222 raise TypeError("Shift amount must be unsigned")
223 def __lshift__(self
, other
):
224 other
= Value
.cast(other
)
225 other
.__check
_shamt
()
226 return Operator("<<", [self
, other
])
227 def __rlshift__(self
, other
):
229 return Operator("<<", [other
, self
])
230 def __rshift__(self
, other
):
231 other
= Value
.cast(other
)
232 other
.__check
_shamt
()
233 return Operator(">>", [self
, other
])
234 def __rrshift__(self
, other
):
236 return Operator(">>", [other
, self
])
238 def __and__(self
, other
):
239 return Operator("&", [self
, other
])
240 def __rand__(self
, other
):
241 return Operator("&", [other
, self
])
242 def __xor__(self
, other
):
243 return Operator("^", [self
, other
])
244 def __rxor__(self
, other
):
245 return Operator("^", [other
, self
])
246 def __or__(self
, other
):
247 return Operator("|", [self
, other
])
248 def __ror__(self
, other
):
249 return Operator("|", [other
, self
])
251 def __eq__(self
, other
):
252 return Operator("==", [self
, other
])
253 def __ne__(self
, other
):
254 return Operator("!=", [self
, other
])
255 def __lt__(self
, other
):
256 return Operator("<", [self
, other
])
257 def __le__(self
, other
):
258 return Operator("<=", [self
, other
])
259 def __gt__(self
, other
):
260 return Operator(">", [self
, other
])
261 def __ge__(self
, other
):
262 return Operator(">=", [self
, other
])
265 width
, signed
= self
.shape()
267 return Mux(self
>= 0, self
, -self
)
272 return self
.shape().width
274 def __getitem__(self
, key
):
276 if isinstance(key
, int):
277 if key
not in range(-n
, n
):
278 raise IndexError(f
"Index {key} is out of bounds for a {n}-bit value")
281 return Slice(self
, key
, key
+ 1)
282 elif isinstance(key
, slice):
283 start
, stop
, step
= key
.indices(n
)
285 return Cat(self
[i
] for i
in range(start
, stop
, step
))
286 return Slice(self
, start
, stop
)
288 raise TypeError("Cannot index value with {}".format(repr(key
)))
290 def as_unsigned(self
):
291 """Conversion to unsigned.
296 This ``Value`` reinterpreted as a unsigned integer.
298 return Operator("u", [self
])
301 """Conversion to signed.
306 This ``Value`` reinterpreted as a signed integer.
308 return Operator("s", [self
])
311 """Conversion to boolean.
316 ``1`` if any bits are set, ``0`` otherwise.
318 return Operator("b", [self
])
321 """Check if any bits are ``1``.
326 ``1`` if any bits are set, ``0`` otherwise.
328 return Operator("r|", [self
])
331 """Check if all bits are ``1``.
336 ``1`` if all bits are set, ``0`` otherwise.
338 return Operator("r&", [self
])
341 """Compute pairwise exclusive-or of every bit.
346 ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set.
348 return Operator("r^", [self
])
350 def implies(premise
, conclusion
):
356 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
358 return ~premise | conclusion
360 def bit_select(self
, offset
, width
):
361 """Part-select with bit granularity.
363 Selects a constant width but variable offset part of a ``Value``, such that successive
364 parts overlap by all but 1 bit.
369 Index of first selected bit.
371 Number of selected bits.
376 Selected part of the ``Value``
378 offset
= Value
.cast(offset
)
379 if type(offset
) is Const
and isinstance(width
, int):
380 return self
[offset
.value
:offset
.value
+ width
]
381 return Part(self
, offset
, width
, stride
=1, src_loc_at
=1)
383 def word_select(self
, offset
, width
):
384 """Part-select with word granularity.
386 Selects a constant width but variable offset part of a ``Value``, such that successive
387 parts do not overlap.
392 Index of first selected word.
394 Number of selected bits.
399 Selected part of the ``Value``
401 offset
= Value
.cast(offset
)
402 if type(offset
) is Const
and isinstance(width
, int):
403 return self
[offset
.value
* width
:(offset
.value
+ 1) * width
]
404 return Part(self
, offset
, width
, stride
=width
, src_loc_at
=1)
406 def matches(self
, *patterns
):
409 Matches against a set of patterns, which may be integers or bit strings, recognizing
410 the same grammar as ``Case()``.
414 patterns : int or str
415 Patterns to match against.
420 ``1`` if any pattern matches the value, ``0`` otherwise.
423 for pattern
in patterns
:
424 if not isinstance(pattern
, (int, str, Enum
)):
425 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
428 if isinstance(pattern
, str) and any(bit
not in "01- \t" for bit
in pattern
):
429 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
430 "bits, and may include whitespace"
432 if (isinstance(pattern
, str) and
433 len("".join(pattern
.split())) != len(self
)):
434 raise SyntaxError("Match pattern '{}' must have the same width as match value "
436 .format(pattern
, len(self
)))
437 if isinstance(pattern
, int) and bits_for(pattern
) > len(self
):
438 warnings
.warn("Match pattern '{:b}' is wider than match value "
439 "(which has width {}); comparison will never be true"
440 .format(pattern
, len(self
)),
441 SyntaxWarning, stacklevel
=3)
443 if isinstance(pattern
, str):
444 pattern
= "".join(pattern
.split()) # remove whitespace
445 mask
= int(pattern
.replace("0", "1").replace("-", "0"), 2)
446 pattern
= int(pattern
.replace("-", "0"), 2)
447 matches
.append((self
& mask
) == pattern
)
448 elif isinstance(pattern
, int):
449 matches
.append(self
== pattern
)
450 elif isinstance(pattern
, Enum
):
451 matches
.append(self
== pattern
.value
)
456 elif len(matches
) == 1:
459 return Cat(*matches
).any()
461 def shift_left(self
, amount
):
462 """Shift left by constant amount.
472 If the amount is positive, the input shifted left. Otherwise, the input shifted right.
474 if not isinstance(amount
, int):
475 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
477 return self
.shift_right(-amount
)
478 if self
.shape().signed
:
479 return Cat(Const(0, amount
), self
).as_signed()
481 return Cat(Const(0, amount
), self
) # unsigned
483 def shift_right(self
, amount
):
484 """Shift right by constant amount.
494 If the amount is positive, the input shifted right. Otherwise, the input shifted left.
496 if not isinstance(amount
, int):
497 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
499 return self
.shift_left(-amount
)
500 if self
.shape().signed
:
501 return self
[amount
:].as_signed()
503 return self
[amount
:] # unsigned
505 def rotate_left(self
, amount
):
506 """Rotate left by constant amount.
516 If the amount is positive, the input rotated left. Otherwise, the input rotated right.
518 if not isinstance(amount
, int):
519 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
521 return Cat(self
[-amount
:], self
[:-amount
]) # meow :3
523 def rotate_right(self
, amount
):
524 """Rotate right by constant amount.
534 If the amount is positive, the input rotated right. Otherwise, the input rotated right.
536 if not isinstance(amount
, int):
537 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
539 return Cat(self
[amount
:], self
[:amount
])
547 Value to be assigned.
552 Assignment statement that can be used in combinatorial or synchronous context.
554 return Assign(self
, value
, src_loc_at
=1)
558 """Bit width and signedness of a value.
567 >>> Signal(8).shape()
568 Shape(width=8, signed=False)
569 >>> Const(0xaa).shape()
570 Shape(width=8, signed=False)
574 def _lhs_signals(self
):
575 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
578 def _rhs_signals(self
):
582 raise TypeError("Value {!r} cannot be evaluated as constant".format(self
))
589 """A constant, literal integer value.
594 shape : int or tuple or None
595 Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
596 in this constant and whether it is signed (can represent negative values).
597 ``shape`` defaults to the minimum possible width and signedness of ``value``.
607 def normalize(value
, shape
):
608 width
, signed
= shape
609 mask
= (1 << width
) - 1
611 if signed
and value
>> (width
- 1):
615 def __init__(self
, value
, shape
=None, *, src_loc_at
=0):
616 # We deliberately do not call Value.__init__ here.
617 self
.value
= int(value
)
619 shape
= Shape(bits_for(self
.value
), signed
=self
.value
< 0)
620 elif isinstance(shape
, int):
621 shape
= Shape(shape
, signed
=self
.value
< 0)
623 shape
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
624 self
.width
, self
.signed
= shape
625 self
.value
= self
.normalize(self
.value
, shape
)
628 return Shape(self
.width
, self
.signed
)
630 def _rhs_signals(self
):
637 return "(const {}'{}d{})".format(self
.width
, "s" if self
.signed
else "", self
.value
)
640 C
= Const
# shorthand
643 class AnyValue(Value
, DUID
):
644 def __init__(self
, shape
, *, src_loc_at
=0):
645 super().__init
__(src_loc_at
=src_loc_at
)
646 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
647 if not isinstance(self
.width
, int) or self
.width
< 0:
648 raise TypeError("Width must be a non-negative integer, not {!r}"
652 return Shape(self
.width
, self
.signed
)
654 def _rhs_signals(self
):
659 class AnyConst(AnyValue
):
661 return "(anyconst {}'{})".format(self
.width
, "s" if self
.signed
else "")
665 class AnySeq(AnyValue
):
667 return "(anyseq {}'{})".format(self
.width
, "s" if self
.signed
else "")
671 class Operator(Value
):
672 def __init__(self
, operator
, operands
, *, src_loc_at
=0):
673 super().__init
__(src_loc_at
=1 + src_loc_at
)
674 self
.operator
= operator
675 self
.operands
= [Value
.cast(op
) for op
in operands
]
678 def _bitwise_binary_shape(a_shape
, b_shape
):
679 a_bits
, a_sign
= a_shape
680 b_bits
, b_sign
= b_shape
681 if not a_sign
and not b_sign
:
682 # both operands unsigned
683 return Shape(max(a_bits
, b_bits
), False)
684 elif a_sign
and b_sign
:
685 # both operands signed
686 return Shape(max(a_bits
, b_bits
), True)
687 elif not a_sign
and b_sign
:
688 # first operand unsigned (add sign bit), second operand signed
689 return Shape(max(a_bits
+ 1, b_bits
), True)
691 # first signed, second operand unsigned (add sign bit)
692 return Shape(max(a_bits
, b_bits
+ 1), True)
694 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
695 if len(op_shapes
) == 1:
696 (a_width
, a_signed
), = op_shapes
697 if self
.operator
in ("+", "~"):
698 return Shape(a_width
, a_signed
)
699 if self
.operator
== "-":
700 return Shape(a_width
+ 1, True)
701 if self
.operator
in ("b", "r|", "r&", "r^"):
702 return Shape(1, False)
703 if self
.operator
== "u":
704 return Shape(a_width
, False)
705 if self
.operator
== "s":
706 return Shape(a_width
, True)
707 elif len(op_shapes
) == 2:
708 (a_width
, a_signed
), (b_width
, b_signed
) = op_shapes
709 if self
.operator
in ("+", "-"):
710 width
, signed
= _bitwise_binary_shape(*op_shapes
)
711 return Shape(width
+ 1, signed
)
712 if self
.operator
== "*":
713 return Shape(a_width
+ b_width
, a_signed
or b_signed
)
714 if self
.operator
in ("//", "%"):
716 return Shape(a_width
, a_signed
)
717 if self
.operator
in ("<", "<=", "==", "!=", ">", ">="):
718 return Shape(1, False)
719 if self
.operator
in ("&", "^", "|"):
720 return _bitwise_binary_shape(*op_shapes
)
721 if self
.operator
== "<<":
723 return Shape(a_width
+ 2 ** b_width
- 1, a_signed
)
724 if self
.operator
== ">>":
726 return Shape(a_width
, a_signed
)
727 elif len(op_shapes
) == 3:
728 if self
.operator
== "m":
729 s_shape
, a_shape
, b_shape
= op_shapes
730 return _bitwise_binary_shape(a_shape
, b_shape
)
731 raise NotImplementedError("Operator {}/{} not implemented"
732 .format(self
.operator
, len(op_shapes
))) # :nocov:
734 def _rhs_signals(self
):
735 return union(op
._rhs
_signals
() for op
in self
.operands
)
738 return "({} {})".format(self
.operator
, " ".join(map(repr, self
.operands
)))
741 def Mux(sel
, val1
, val0
):
742 if isinstance(sel
, bool): # one instance where Mux is passed an actual bool
743 sel
= Value
.cast(sel
)
744 return sel
.__Mux
__(val1
, val0
)
747 def _InternalMux(sel
, val1
, val0
):
748 """Choose between two values.
761 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
763 sel
= Value
.cast(sel
)
766 return Operator("m", [sel
, val1
, val0
])
771 def __init__(self
, value
, start
, stop
, *, src_loc_at
=0):
772 if not isinstance(start
, int):
773 raise TypeError("Slice start must be an integer, not {!r}".format(start
))
774 if not isinstance(stop
, int):
775 raise TypeError("Slice stop must be an integer, not {!r}".format(stop
))
778 if start
not in range(-(n
+1), n
+1):
779 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
782 if stop
not in range(-(n
+1), n
+1):
783 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop
, n
))
787 raise IndexError("Slice start {} must be less than slice stop {}".format(start
, stop
))
789 super().__init
__(src_loc_at
=src_loc_at
)
790 self
.value
= Value
.cast(value
)
791 self
.start
= int(start
)
792 self
.stop
= int(stop
)
795 return Shape(self
.stop
- self
.start
)
797 def _lhs_signals(self
):
798 return self
.value
._lhs
_signals
()
800 def _rhs_signals(self
):
801 return self
.value
._rhs
_signals
()
804 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.stop
)
809 def __init__(self
, value
, offset
, width
, stride
=1, *, src_loc_at
=0):
810 if not isinstance(width
, int) or width
< 0:
811 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width
))
812 if not isinstance(stride
, int) or stride
<= 0:
813 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride
))
815 super().__init
__(src_loc_at
=src_loc_at
)
817 self
.offset
= Value
.cast(offset
)
822 return Shape(self
.width
)
824 def _lhs_signals(self
):
825 return self
.value
._lhs
_signals
()
827 def _rhs_signals(self
):
828 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
831 return "(part {} {} {} {})".format(repr(self
.value
), repr(self
.offset
),
832 self
.width
, self
.stride
)
836 def Cat(*args
, src_loc_at
=0):
837 """Concatenate values.
839 Behaviour is required to be identical to _InternalCat.
840 The first argument "defines" the way that all others are
841 handled. If the first argument is derived from UserValue,
842 it is not downcast to a type Value because doing so would
843 lose the opportunity for "redirection" (Value.__Cat__ would
846 # flatten the args and convert to tuple (not a generator)
847 args
= tuple(flatten(args
))
848 # check if there are no arguments (zero-length Signal).
850 return _InternalCat(*args
, src_loc_at
=src_loc_at
)
851 # determine if the first is a UserValue.
852 if isinstance(args
[0], UserValue
):
853 first
= args
[0] # take UserValue directly, do not downcast
855 first
= Value
.cast(args
[0]) # ok to downcast to Value
856 # all other arguments are safe to downcast to Value
857 rest
= [Value
.cast(v
) for v
in flatten(args
[1:])]
858 # assume first item defines the "handling" for all others
859 return first
.__Cat
__(*rest
, src_loc_at
=src_loc_at
)
862 class _InternalCat(Value
):
863 """Concatenate values.
865 Form a compound ``Value`` from several smaller ones by concatenation.
866 The first argument occupies the lower bits of the result.
867 The return value can be used on either side of an assignment, that
868 is, the concatenated value can be used as an argument on the RHS or
869 as a target on the LHS. If it is used on the LHS, it must solely
870 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
871 meeting these properties. The bit length of the return value is the sum of
872 the bit lengths of the arguments::
874 len(Cat(args)) == sum(len(arg) for arg in args)
878 *args : Values or iterables of Values, inout
879 ``Value`` s to be concatenated.
884 Resulting ``Value`` obtained by concatentation.
886 def __init__(self
, *args
, src_loc_at
=0):
887 super().__init
__(src_loc_at
=src_loc_at
)
888 self
.parts
= [Value
.cast(v
) for v
in flatten(args
)]
891 return Shape(sum(len(part
) for part
in self
.parts
))
893 def _lhs_signals(self
):
894 return union((part
._lhs
_signals
() for part
in self
.parts
), start
=SignalSet())
896 def _rhs_signals(self
):
897 return union((part
._rhs
_signals
() for part
in self
.parts
), start
=SignalSet())
901 for part
in reversed(self
.parts
):
903 value |
= part
._as
_const
()
907 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
911 def Repl(value
, count
, *, src_loc_at
=0):
912 return value
.__Repl
__(count
, src_loc_at
=src_loc_at
)
915 class _InternalRepl(Value
):
918 An input value is replicated (repeated) several times
919 to be used on the RHS of assignments::
921 len(Repl(s, n)) == len(s) * n
926 Input value to be replicated.
928 Number of replications.
935 def __init__(self
, value
, count
, *, src_loc_at
=0):
936 if not isinstance(count
, int) or count
< 0:
937 raise TypeError("Replication count must be a non-negative integer, not {!r}"
940 super().__init
__(src_loc_at
=src_loc_at
)
941 self
.value
= Value
.cast(value
)
945 return Shape(len(self
.value
) * self
.count
)
947 def _rhs_signals(self
):
948 return self
.value
._rhs
_signals
()
951 return "(repl {!r} {})".format(self
.value
, self
.count
)
955 class Signal(Value
, DUID
):
956 """A varying integer value.
960 shape : ``Shape``-castable object or None
961 Specification for the number of bits in this ``Signal`` and its signedness (whether it
962 can represent negative values). See ``Shape.cast`` for details.
963 If not specified, ``shape`` defaults to 1-bit and non-signed.
965 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
966 name this ``Signal`` is assigned to.
967 reset : int or integral Enum
968 Reset (synchronous) or default (combinatorial) value.
969 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
970 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
971 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
972 assumes its ``reset`` value. Defaults to 0.
974 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
975 The ``reset`` value is only used as a combinatorial default or as the initial value.
976 Defaults to ``False``.
978 Dictionary of synthesis attributes.
979 decoder : function or Enum
980 A function converting integer signal values to human-readable strings (e.g. FSM state
981 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
982 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
996 def __init__(self
, shape
=None, *, name
=None, reset
=0, reset_less
=False,
997 attrs
=None, decoder
=None, src_loc_at
=0):
998 super().__init
__(src_loc_at
=src_loc_at
)
1000 if name
is not None and not isinstance(name
, str):
1001 raise TypeError("Name must be a string, not {!r}".format(name
))
1002 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$signal")
1006 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
1008 if isinstance(reset
, Enum
):
1010 if not isinstance(reset
, int):
1011 raise TypeError("Reset value has to be an int or an integral Enum")
1013 reset_width
= bits_for(reset
, self
.signed
)
1014 if reset
!= 0 and reset_width
> self
.width
:
1015 warnings
.warn("Reset value {!r} requires {} bits to represent, but the signal "
1017 .format(reset
, reset_width
, self
.width
),
1018 SyntaxWarning, stacklevel
=2 + src_loc_at
)
1021 self
.reset_less
= bool(reset_less
)
1023 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
1025 if decoder
is None and isinstance(shape
, type) and issubclass(shape
, Enum
):
1027 if isinstance(decoder
, type) and issubclass(decoder
, Enum
):
1028 def enum_decoder(value
):
1030 return "{0.name:}/{0.value:}".format(decoder(value
))
1033 self
.decoder
= enum_decoder
1034 self
._enum
_class
= decoder
1036 self
.decoder
= decoder
1037 self
._enum
_class
= None
1039 # Not a @classmethod because nmigen.compat requires it.
1041 def like(other
, *, name
=None, name_suffix
=None, src_loc_at
=0, **kwargs
):
1042 """Create Signal based on another.
1047 Object to base this Signal on.
1049 if name
is not None:
1050 new_name
= str(name
)
1051 elif name_suffix
is not None:
1052 new_name
= other
.name
+ str(name_suffix
)
1054 new_name
= tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$like")
1055 kw
= dict(shape
=Value
.cast(other
).shape(), name
=new_name
)
1056 if isinstance(other
, Signal
):
1057 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
1058 attrs
=other
.attrs
, decoder
=other
.decoder
)
1060 return Signal(**kw
, src_loc_at
=1 + src_loc_at
)
1063 return Shape(self
.width
, self
.signed
)
1065 def _lhs_signals(self
):
1066 return SignalSet((self
,))
1068 def _rhs_signals(self
):
1069 return SignalSet((self
,))
1072 return "(sig {})".format(self
.name
)
1076 class ClockSignal(Value
):
1077 """Clock signal for a clock domain.
1079 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
1080 All of these signals ultimately refer to the same signal, but they can be manipulated
1081 independently of the clock domain, even before the clock domain is created.
1086 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
1088 def __init__(self
, domain
="sync", *, src_loc_at
=0):
1089 super().__init
__(src_loc_at
=src_loc_at
)
1090 if not isinstance(domain
, str):
1091 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1092 if domain
== "comb":
1093 raise ValueError("Domain '{}' does not have a clock".format(domain
))
1094 self
.domain
= domain
1099 def _lhs_signals(self
):
1100 return SignalSet((self
,))
1102 def _rhs_signals(self
):
1103 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
1106 return "(clk {})".format(self
.domain
)
1110 class ResetSignal(Value
):
1111 """Reset signal for a clock domain.
1113 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
1114 All of these signals ultimately refer to the same signal, but they can be manipulated
1115 independently of the clock domain, even before the clock domain is created.
1120 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
1121 allow_reset_less : bool
1122 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
1124 def __init__(self
, domain
="sync", allow_reset_less
=False, *, src_loc_at
=0):
1125 super().__init
__(src_loc_at
=src_loc_at
)
1126 if not isinstance(domain
, str):
1127 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1128 if domain
== "comb":
1129 raise ValueError("Domain '{}' does not have a reset".format(domain
))
1130 self
.domain
= domain
1131 self
.allow_reset_less
= allow_reset_less
1136 def _lhs_signals(self
):
1137 return SignalSet((self
,))
1139 def _rhs_signals(self
):
1140 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
1143 return "(rst {})".format(self
.domain
)
1146 class Array(MutableSequence
):
1147 """Addressable multiplexer.
1149 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
1152 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
1153 assignments, provided that all elements of the array are values. The array proxy also supports
1154 attribute access and further indexing, each returning another array proxy; this means that
1155 the results of indexing into arrays, arrays of records, and arrays of arrays can all
1156 be used as first-class values.
1158 It is an error to change an array or any of its elements after an array proxy was created.
1159 Changing the array directly will raise an exception. However, it is not possible to detect
1160 the elements being modified; if an element's attribute or element is modified after the proxy
1161 for it has been created, the proxy will refer to stale data.
1168 gpios = Array(Signal() for _ in range(10))
1170 m.d.sync += gpios[bus.addr].eq(bus.w_data)
1172 m.d.sync += bus.r_data.eq(gpios[bus.addr])
1174 Multidimensional array::
1176 mult = Array(Array(x * y for y in range(10)) for x in range(10))
1177 a = Signal.range(10)
1178 b = Signal.range(10)
1180 m.d.comb += r.eq(mult[a][b])
1188 buses = Array(Record(layout) for busno in range(4))
1189 master = Record(layout)
1191 buses[sel].r_en.eq(master.r_en),
1192 master.r_data.eq(buses[sel].r_data),
1195 def __init__(self
, iterable
=()):
1196 self
._inner
= list(iterable
)
1197 self
._proxy
_at
= None
1198 self
._mutable
= True
1200 def __getitem__(self
, index
):
1201 if isinstance(index
, Value
):
1203 self
._proxy
_at
= tracer
.get_src_loc()
1204 self
._mutable
= False
1205 return ArrayProxy(self
, index
)
1207 return self
._inner
[index
]
1210 return len(self
._inner
)
1212 def _check_mutability(self
):
1213 if not self
._mutable
:
1214 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1215 "at {}:{}".format(*self
._proxy
_at
))
1217 def __setitem__(self
, index
, value
):
1218 self
._check
_mutability
()
1219 self
._inner
[index
] = value
1221 def __delitem__(self
, index
):
1222 self
._check
_mutability
()
1223 del self
._inner
[index
]
1225 def insert(self
, index
, value
):
1226 self
._check
_mutability
()
1227 self
._inner
.insert(index
, value
)
1230 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
1231 ", ".join(map(repr, self
._inner
)))
1235 class ArrayProxy(Value
):
1236 def __init__(self
, elems
, index
, *, src_loc_at
=0):
1237 super().__init
__(src_loc_at
=1 + src_loc_at
)
1239 self
.index
= Value
.cast(index
)
1241 def __getattr__(self
, attr
):
1242 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
1244 def __getitem__(self
, index
):
1245 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
1247 def _iter_as_values(self
):
1248 return (Value
.cast(elem
) for elem
in self
.elems
)
1251 unsigned_width
= signed_width
= 0
1252 has_unsigned
= has_signed
= False
1253 for elem_width
, elem_signed
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
1256 signed_width
= max(signed_width
, elem_width
)
1259 unsigned_width
= max(unsigned_width
, elem_width
)
1260 # The shape of the proxy must be such that it preserves the mathematical value of the array
1261 # elements. I.e., shape-wise, an array proxy must be identical to an equivalent mux tree.
1262 # To ensure this holds, if the array contains both signed and unsigned values, make sure
1263 # that every unsigned value is zero-extended by at least one bit.
1264 if has_signed
and has_unsigned
and unsigned_width
>= signed_width
:
1265 # Array contains both signed and unsigned values, and at least one of the unsigned
1266 # values won't be zero-extended otherwise.
1267 return signed(unsigned_width
+ 1)
1269 # Array contains values of the same signedness, or else all of the unsigned values
1270 # are zero-extended.
1271 return Shape(max(unsigned_width
, signed_width
), has_signed
)
1273 def _lhs_signals(self
):
1274 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()),
1278 def _rhs_signals(self
):
1279 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()),
1281 return self
.index
._rhs
_signals
() | signals
1284 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
1287 # TODO(nmigen-0.4): remove
1288 class UserValue(Value
):
1289 """Value with custom lowering.
1291 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1292 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1293 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1294 value when required.
1296 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1297 nMigen's view of representation of all values stays internally consistent. If the class
1298 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1299 it is not mutated in a way that changes its representation.
1301 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1302 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1303 * Querying the shape using ``.shape()`` or ``len()``;
1304 * Creating a similarly shaped signal using ``Signal.like``;
1305 * Indexing or iterating through individual bits;
1306 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1308 @deprecated("instead of `UserValue`, use `ValueCastable`", stacklevel
=3)
1309 def __init__(self
, *, src_loc_at
=0):
1310 super().__init
__(src_loc_at
=1 + src_loc_at
)
1311 self
.__lowered
= None
1315 """Conversion to a concrete representation."""
1318 def _lazy_lower(self
):
1319 if self
.__lowered
is None:
1320 lowered
= self
.lower()
1321 if isinstance(lowered
, UserValue
):
1322 lowered
= lowered
._lazy
_lower
()
1323 self
.__lowered
= Value
.cast(lowered
)
1324 return self
.__lowered
1327 return self
._lazy
_lower
().shape()
1329 def _lhs_signals(self
):
1330 return self
._lazy
_lower
()._lhs
_signals
()
1332 def _rhs_signals(self
):
1333 return self
._lazy
_lower
()._rhs
_signals
()
1336 class ValueCastable
:
1337 """Base class for classes which can be cast to Values.
1339 A ``ValueCastable`` can be cast to ``Value``, meaning its precise representation does not have
1340 to be immediately known. This is useful in certain metaprogramming scenarios. Instead of
1341 providing fixed semantics upfront, it is kept abstract for as long as possible, only being
1342 cast to a concrete nMigen value when required.
1344 Note that it is necessary to ensure that nMigen's view of representation of all values stays
1345 internally consistent. The class deriving from ``ValueCastable`` must decorate the ``as_value``
1346 method with the ``lowermethod`` decorator, which ensures that all calls to ``as_value`` return
1347 the same ``Value`` representation. If the class deriving from ``ValueCastable`` is mutable,
1348 it is up to the user to ensure that it is not mutated in a way that changes its representation
1349 after the first call to ``as_value``.
1351 def __new__(cls
, *args
, **kwargs
):
1352 self
= super().__new
__(cls
)
1353 if not hasattr(self
, "as_value"):
1354 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must override "
1355 "the `as_value` method")
1357 if not hasattr(self
.as_value
, "_ValueCastable__memoized"):
1358 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must decorate "
1359 "the `as_value` method with the `ValueCastable.lowermethod` decorator")
1363 def lowermethod(func
):
1364 """Decorator to memoize lowering methods.
1366 Ensures the decorated method is called only once, with subsequent method calls returning the
1367 object returned by the first first method call.
1369 This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` subclasses.
1370 This is to ensure that nMigen's view of representation of all values stays internally
1373 @functools.wraps(func
)
1374 def wrapper_memoized(self
, *args
, **kwargs
):
1375 if not hasattr(self
, "_ValueCastable__lowered_to"):
1376 self
.__lowered
_to
= func(self
, *args
, **kwargs
)
1377 return self
.__lowered
_to
1378 wrapper_memoized
.__memoized
= True
1379 return wrapper_memoized
1383 class Sample(Value
):
1384 """Value from the past.
1386 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1387 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1388 to the value of the expression calculated as if each signal had its reset value.
1390 def __init__(self
, expr
, clocks
, domain
, *, src_loc_at
=0):
1391 super().__init
__(src_loc_at
=1 + src_loc_at
)
1392 self
.value
= Value
.cast(expr
)
1393 self
.clocks
= int(clocks
)
1394 self
.domain
= domain
1395 if not isinstance(self
.value
, (Const
, Signal
, ClockSignal
, ResetSignal
, Initial
)):
1396 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1397 .format(self
.value
))
1399 raise ValueError("Cannot sample a value {} cycles in the future"
1400 .format(-self
.clocks
))
1401 if not (self
.domain
is None or isinstance(self
.domain
, str)):
1402 raise TypeError("Domain name must be a string or None, not {!r}"
1403 .format(self
.domain
))
1406 return self
.value
.shape()
1408 def _rhs_signals(self
):
1409 return SignalSet((self
,))
1412 return "(sample {!r} @ {}[{}])".format(
1413 self
.value
, "<default>" if self
.domain
is None else self
.domain
, self
.clocks
)
1416 def Past(expr
, clocks
=1, domain
=None):
1417 return Sample(expr
, clocks
, domain
)
1420 def Stable(expr
, clocks
=0, domain
=None):
1421 return Sample(expr
, clocks
+ 1, domain
) == Sample(expr
, clocks
, domain
)
1424 def Rose(expr
, clocks
=0, domain
=None):
1425 return ~
Sample(expr
, clocks
+ 1, domain
) & Sample(expr
, clocks
, domain
)
1428 def Fell(expr
, clocks
=0, domain
=None):
1429 return Sample(expr
, clocks
+ 1, domain
) & ~
Sample(expr
, clocks
, domain
)
1433 class Initial(Value
):
1434 """Start indicator, for model checking.
1436 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1438 def __init__(self
, *, src_loc_at
=0):
1439 super().__init
__(src_loc_at
=src_loc_at
)
1444 def _rhs_signals(self
):
1445 return SignalSet((self
,))
1451 class _StatementList(list):
1453 return "({})".format(" ".join(map(repr, self
)))
1457 def __init__(self
, *, src_loc_at
=0):
1458 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
1462 if isinstance(obj
, Iterable
):
1463 return _StatementList(list(chain
.from_iterable(map(Statement
.cast
, obj
))))
1465 if isinstance(obj
, Statement
):
1466 return _StatementList([obj
])
1468 raise TypeError("Object {!r} is not an nMigen statement".format(obj
))
1472 def Assign(lhs
, rhs
, *, src_loc_at
=0):
1473 return lhs
.__Assign
__(rhs
, src_loc_at
=src_loc_at
)
1476 class _InternalAssign(Statement
):
1477 def __init__(self
, lhs
, rhs
, *, src_loc_at
=0):
1478 super().__init
__(src_loc_at
=src_loc_at
)
1479 self
.lhs
= Value
.cast(lhs
)
1480 self
.rhs
= Value
.cast(rhs
)
1482 def _lhs_signals(self
):
1483 return self
.lhs
._lhs
_signals
()
1485 def _rhs_signals(self
):
1486 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
1489 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
1492 class UnusedProperty(UnusedMustUse
):
1496 class Property(Statement
, MustUse
):
1497 _MustUse__warning
= UnusedProperty
1499 def __init__(self
, test
, *, _check
=None, _en
=None, src_loc_at
=0):
1500 super().__init
__(src_loc_at
=src_loc_at
)
1501 self
.test
= Value
.cast(test
)
1502 self
._check
= _check
1504 if self
._check
is None:
1505 self
._check
= Signal(reset_less
=True, name
="${}$check".format(self
._kind
))
1506 self
._check
.src_loc
= self
.src_loc
1508 self
._en
= Signal(reset_less
=True, name
="${}$en".format(self
._kind
))
1509 self
._en
.src_loc
= self
.src_loc
1511 def _lhs_signals(self
):
1512 return SignalSet((self
._en
, self
._check
))
1514 def _rhs_signals(self
):
1515 return self
.test
._rhs
_signals
()
1518 return "({} {!r})".format(self
._kind
, self
.test
)
1522 class Assert(Property
):
1527 class Assume(Property
):
1532 class Cover(Property
):
1537 def Switch(test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1538 return test
.__Switch
__(cases
, src_loc
=src_loc
, src_loc_at
=src_loc_at
,
1539 case_src_locs
=case_src_locs
)
1542 class _InternalSwitch(Statement
):
1543 def __init__(self
, test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1545 super().__init
__(src_loc_at
=src_loc_at
)
1547 # Switch is a bit special in terms of location tracking because it is usually created
1548 # long after the control has left the statement that directly caused its creation.
1549 self
.src_loc
= src_loc
1550 # Switch is also a bit special in that its parts also have location information. It can't
1551 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1552 self
.case_src_locs
= {}
1554 self
.test
= Value
.cast(test
)
1555 self
.cases
= OrderedDict()
1556 for orig_keys
, stmts
in cases
.items():
1557 # Map: None -> (); key -> (key,); (key...) -> (key...)
1561 if not isinstance(keys
, tuple):
1563 # Map: 2 -> "0010"; "0010" -> "0010"
1565 key_mask
= (1 << len(self
.test
)) - 1
1567 if isinstance(key
, str):
1568 key
= "".join(key
.split()) # remove whitespace
1569 elif isinstance(key
, int):
1570 key
= format(key
& key_mask
, "b").rjust(len(self
.test
), "0")
1571 elif isinstance(key
, Enum
):
1572 key
= format(key
.value
& key_mask
, "b").rjust(len(self
.test
), "0")
1574 raise TypeError("Object {!r} cannot be used as a switch key"
1576 assert len(key
) == len(self
.test
)
1577 new_keys
= (*new_keys
, key
)
1578 if not isinstance(stmts
, Iterable
):
1580 self
.cases
[new_keys
] = Statement
.cast(stmts
)
1581 if orig_keys
in case_src_locs
:
1582 self
.case_src_locs
[new_keys
] = case_src_locs
[orig_keys
]
1584 def _lhs_signals(self
):
1585 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1589 def _rhs_signals(self
):
1590 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1592 return self
.test
._rhs
_signals
() | signals
1595 def case_repr(keys
, stmts
):
1596 stmts_repr
= " ".join(map(repr, stmts
))
1598 return "(default {})".format(stmts_repr
)
1599 elif len(keys
) == 1:
1600 return "(case {} {})".format(keys
[0], stmts_repr
)
1602 return "(case ({}) {})".format(" ".join(keys
), stmts_repr
)
1603 case_reprs
= [case_repr(keys
, stmts
) for keys
, stmts
in self
.cases
.items()]
1604 return "(switch {!r} {})".format(self
.test
, " ".join(case_reprs
))
1607 class _MappedKeyCollection(metaclass
=ABCMeta
):
1609 def _map_key(self
, key
):
1613 def _unmap_key(self
, key
):
1617 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
1618 def __init__(self
, pairs
=()):
1619 self
._storage
= OrderedDict()
1620 for key
, value
in pairs
:
1623 def __getitem__(self
, key
):
1624 key
= None if key
is None else self
._map
_key
(key
)
1625 return self
._storage
[key
]
1627 def __setitem__(self
, key
, value
):
1628 key
= None if key
is None else self
._map
_key
(key
)
1629 self
._storage
[key
] = value
1631 def __delitem__(self
, key
):
1632 key
= None if key
is None else self
._map
_key
(key
)
1633 del self
._storage
[key
]
1636 for key
in self
._storage
:
1640 yield self
._unmap
_key
(key
)
1642 def __eq__(self
, other
):
1643 if not isinstance(other
, type(self
)):
1645 if len(self
) != len(other
):
1647 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
1650 if self
._storage
[ak
] != other
._storage
[bk
]:
1655 return len(self
._storage
)
1658 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
1659 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
1663 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
1664 def __init__(self
, elements
=()):
1665 self
._storage
= OrderedDict()
1666 for elem
in elements
:
1669 def add(self
, value
):
1670 self
._storage
[self
._map
_key
(value
)] = None
1672 def update(self
, values
):
1673 for value
in values
:
1676 def discard(self
, value
):
1678 del self
._storage
[self
._map
_key
(value
)]
1680 def __contains__(self
, value
):
1681 return self
._map
_key
(value
) in self
._storage
1684 for key
in [k
for k
in self
._storage
]:
1685 yield self
._unmap
_key
(key
)
1688 return len(self
._storage
)
1691 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
1692 ", ".join(repr(x
) for x
in self
))
1696 def __init__(self
, value
):
1697 self
.value
= Value
.cast(value
)
1698 if isinstance(self
.value
, Const
):
1699 self
._hash
= hash(self
.value
.value
)
1700 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1701 self
._hash
= hash(self
.value
.duid
)
1702 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1703 self
._hash
= hash(self
.value
.domain
)
1704 elif isinstance(self
.value
, Operator
):
1705 self
._hash
= hash((self
.value
.operator
,
1706 tuple(ValueKey(o
) for o
in self
.value
.operands
)))
1707 elif isinstance(self
.value
, Slice
):
1708 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.stop
))
1709 elif isinstance(self
.value
, Part
):
1710 self
._hash
= hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
1711 self
.value
.width
, self
.value
.stride
))
1712 elif isinstance(self
.value
, _InternalCat
):
1713 self
._hash
= hash(tuple(ValueKey(o
) for o
in self
.value
.parts
))
1714 elif isinstance(self
.value
, ArrayProxy
):
1715 self
._hash
= hash((ValueKey(self
.value
.index
),
1716 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
1717 elif isinstance(self
.value
, Sample
):
1718 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.clocks
, self
.value
.domain
))
1719 elif isinstance(self
.value
, Initial
):
1722 raise TypeError("Object {!r} cannot be used as a key in value collections"
1723 .format(self
.value
))
1728 def __eq__(self
, other
):
1729 if type(other
) is not ValueKey
:
1731 if type(self
.value
) is not type(other
.value
):
1734 if isinstance(self
.value
, Const
):
1735 return self
.value
.value
== other
.value
.value
1736 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1737 return self
.value
is other
.value
1738 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1739 return self
.value
.domain
== other
.value
.domain
1740 elif isinstance(self
.value
, Operator
):
1741 return (self
.value
.operator
== other
.value
.operator
and
1742 len(self
.value
.operands
) == len(other
.value
.operands
) and
1743 all(ValueKey(a
) == ValueKey(b
)
1744 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1745 elif isinstance(self
.value
, Slice
):
1746 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1747 self
.value
.start
== other
.value
.start
and
1748 self
.value
.stop
== other
.value
.stop
)
1749 elif isinstance(self
.value
, Part
):
1750 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1751 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1752 self
.value
.width
== other
.value
.width
and
1753 self
.value
.stride
== other
.value
.stride
)
1754 elif isinstance(self
.value
, _InternalCat
):
1755 return all(ValueKey(a
) == ValueKey(b
)
1756 for a
, b
in zip(self
.value
.parts
, other
.value
.parts
))
1757 elif isinstance(self
.value
, ArrayProxy
):
1758 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1759 len(self
.value
.elems
) == len(other
.value
.elems
) and
1760 all(ValueKey(a
) == ValueKey(b
)
1761 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1762 other
.value
._iter
_as
_values
())))
1763 elif isinstance(self
.value
, Sample
):
1764 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1765 self
.value
.clocks
== other
.value
.clocks
and
1766 self
.value
.domain
== self
.value
.domain
)
1767 elif isinstance(self
.value
, Initial
):
1770 raise TypeError("Object {!r} cannot be used as a key in value collections"
1771 .format(self
.value
))
1773 def __lt__(self
, other
):
1774 if not isinstance(other
, ValueKey
):
1776 if type(self
.value
) != type(other
.value
):
1779 if isinstance(self
.value
, Const
):
1780 return self
.value
< other
.value
1781 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1782 return self
.value
.duid
< other
.value
.duid
1783 elif isinstance(self
.value
, Slice
):
1784 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1785 self
.value
.start
< other
.value
.start
and
1786 self
.value
.end
< other
.value
.end
)
1788 raise TypeError("Object {!r} cannot be used as a key in value collections")
1791 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1794 class ValueDict(_MappedKeyDict
):
1796 _unmap_key
= lambda self
, key
: key
.value
1799 class ValueSet(_MappedKeySet
):
1801 _unmap_key
= lambda self
, key
: key
.value
1805 def __init__(self
, signal
):
1806 self
.signal
= signal
1807 if isinstance(signal
, Signal
):
1808 self
._intern
= (0, signal
.duid
)
1809 elif type(signal
) is ClockSignal
:
1810 self
._intern
= (1, signal
.domain
)
1811 elif type(signal
) is ResetSignal
:
1812 self
._intern
= (2, signal
.domain
)
1814 raise TypeError("Object {!r} is not an nMigen signal".format(signal
))
1817 return hash(self
._intern
)
1819 def __eq__(self
, other
):
1820 if type(other
) is not SignalKey
:
1822 return self
._intern
== other
._intern
1824 def __lt__(self
, other
):
1825 if type(other
) is not SignalKey
:
1826 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal
))
1827 return self
._intern
< other
._intern
1830 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1833 class SignalDict(_MappedKeyDict
):
1834 _map_key
= SignalKey
1835 _unmap_key
= lambda self
, key
: key
.signal
1838 class SignalSet(_MappedKeySet
):
1839 _map_key
= SignalKey
1840 _unmap_key
= lambda self
, key
: key
.signal