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",
20 "Signal", "ClockSignal", "ResetSignal",
21 "UserValue", "ValueCastable",
22 "Sample", "Past", "Stable", "Rose", "Fell", "Initial",
23 "Statement", "Switch",
24 "Property", "Assign", "Assert", "Assume", "Cover",
25 "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "SignalSet",
30 """Deterministic Unique IDentifier."""
33 self
.duid
= DUID
.__next
_uid
38 """Bit width and signedness of a value.
40 A ``Shape`` can be constructed using:
41 * explicit bit width and signedness;
42 * aliases :func:`signed` and :func:`unsigned`;
43 * casting from a variety of objects.
45 A ``Shape`` can be cast from:
46 * an integer, where the integer specifies the bit width;
47 * a range, where the result is wide enough to represent any element of the range, and is
48 signed if any element of the range is signed;
49 * an :class:`Enum` with all integer members or :class:`IntEnum`, where the result is wide
50 enough to represent any member of the enumeration, and is signed if any member of
51 the enumeration is signed.
56 The number of bits in the representation, including the sign bit (if any).
58 If ``False``, the value is unsigned. If ``True``, the value is signed two's complement.
60 def __init__(self
, width
=1, signed
=False):
61 if not isinstance(width
, int) or width
< 0:
62 raise TypeError("Width must be a non-negative integer, not {!r}"
68 return iter((self
.width
, self
.signed
))
71 def cast(obj
, *, src_loc_at
=0):
72 if isinstance(obj
, Shape
):
74 if isinstance(obj
, int):
76 if isinstance(obj
, tuple):
78 warnings
.warn("instead of `{tuple}`, use `{constructor}({width})`"
79 .format(constructor
="signed" if signed
else "unsigned", width
=width
,
81 DeprecationWarning, stacklevel
=2 + src_loc_at
)
82 return Shape(width
, signed
)
83 if isinstance(obj
, range):
85 return Shape(0, obj
.start
< 0)
86 signed
= obj
.start
< 0 or (obj
.stop
- obj
.step
) < 0
87 width
= max(bits_for(obj
.start
, signed
),
88 bits_for(obj
.stop
- obj
.step
, signed
))
89 return Shape(width
, signed
)
90 if isinstance(obj
, type) and issubclass(obj
, Enum
):
91 min_value
= min(member
.value
for member
in obj
)
92 max_value
= max(member
.value
for member
in obj
)
93 if not isinstance(min_value
, int) or not isinstance(max_value
, int):
94 raise TypeError("Only enumerations with integer values can be used "
96 signed
= min_value
< 0 or max_value
< 0
97 width
= max(bits_for(min_value
, signed
), bits_for(max_value
, signed
))
98 return Shape(width
, signed
)
99 raise TypeError("Object {!r} cannot be used as value shape".format(obj
))
103 return "signed({})".format(self
.width
)
105 return "unsigned({})".format(self
.width
)
107 def __eq__(self
, other
):
108 if isinstance(other
, tuple) and len(other
) == 2:
109 width
, signed
= other
110 if isinstance(width
, int) and isinstance(signed
, bool):
111 return self
.width
== width
and self
.signed
== signed
113 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
116 if not isinstance(other
, Shape
):
117 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
120 return self
.width
== other
.width
and self
.signed
== other
.signed
124 """Shorthand for ``Shape(width, signed=False)``."""
125 return Shape(width
, signed
=False)
129 """Shorthand for ``Shape(width, signed=True)``."""
130 return Shape(width
, signed
=True)
133 class Value(metaclass
=ABCMeta
):
136 """Converts ``obj`` to an nMigen value.
138 Booleans and integers are wrapped into a :class:`Const`. Enumerations whose members are
139 all integers are converted to a :class:`Const` with a shape that fits every member.
141 if isinstance(obj
, Value
):
143 if isinstance(obj
, int):
145 if isinstance(obj
, Enum
):
146 return Const(obj
.value
, Shape
.cast(type(obj
)))
147 if isinstance(obj
, ValueCastable
):
148 return obj
.as_value()
149 raise TypeError("Object {!r} cannot be converted to an nMigen value".format(obj
))
151 def __init__(self
, *, src_loc_at
=0):
153 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
155 # These are redirection of "Type (1) - AST " nmigen language constructs
156 # If over-ridden to provide advanced behaviour, the implementation
157 # *MUST NOT* use "Type (2) - dsl.Module" nmigen language constructs
158 # (m.If, m.Else, m.Switch, m.FSM): it creates complications
159 # (recursive dependencies) in dsl.Module.
161 def __Part__(self
, offset
, width
, stride
=1, *, src_loc_at
=0):
162 return _InternalPart(self
, offset
, width
, stride
,
163 src_loc_at
=src_loc_at
)
164 def __Repl__(self
, count
, *, src_loc_at
=0):
165 return _InternalRepl(self
, count
, src_loc_at
=src_loc_at
)
166 def __Cat__(self
, *args
, src_loc_at
=0):
167 return _InternalCat(self
, *args
, src_loc_at
=src_loc_at
)
168 def __Mux__(self
, val1
, val0
):
169 return _InternalMux(self
, val1
, val0
)
170 def __Switch__(self
, cases
, *, src_loc
=None, src_loc_at
=0,
172 return _InternalSwitch(self
, cases
, src_loc
=src_loc
,
173 src_loc_at
=src_loc_at
,
174 case_src_locs
=case_src_locs
)
175 def __Assign__(self
, rhs
, *, src_loc_at
=0):
176 return _InternalAssign(self
, rhs
, src_loc_at
=src_loc_at
)
178 def considered_bool(self
):
179 return len(self
) == 1
182 raise TypeError("Attempted to convert nMigen value to Python boolean")
184 def __invert__(self
):
185 return Operator("~", [self
])
187 return Operator("-", [self
])
189 def __add__(self
, other
):
190 return Operator("+", [self
, other
])
191 def __radd__(self
, other
):
192 return Operator("+", [other
, self
])
193 def __sub__(self
, other
):
194 return Operator("-", [self
, other
])
195 def __rsub__(self
, other
):
196 return Operator("-", [other
, self
])
198 def __mul__(self
, other
):
199 return Operator("*", [self
, other
])
200 def __rmul__(self
, other
):
201 return Operator("*", [other
, self
])
203 def __check_divisor(self
):
204 width
, signed
= self
.shape()
206 # Python's division semantics and Verilog's division semantics differ for negative
207 # divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
208 # completely by prohibiting such division operations.
209 raise NotImplementedError("Division by a signed value is not supported")
210 def __mod__(self
, other
):
211 other
= Value
.cast(other
)
212 other
.__check
_divisor
()
213 return Operator("%", [self
, other
])
214 def __rmod__(self
, other
):
215 self
.__check
_divisor
()
216 return Operator("%", [other
, self
])
217 def __floordiv__(self
, other
):
218 other
= Value
.cast(other
)
219 other
.__check
_divisor
()
220 return Operator("//", [self
, other
])
221 def __rfloordiv__(self
, other
):
222 self
.__check
_divisor
()
223 return Operator("//", [other
, self
])
225 def __check_shamt(self
):
226 width
, signed
= self
.shape()
228 # Neither Python nor HDLs implement shifts by negative values; prohibit any shifts
229 # by a signed value to make sure the shift amount can always be interpreted as
231 raise TypeError("Shift amount must be unsigned")
232 def __lshift__(self
, other
):
233 other
= Value
.cast(other
)
234 other
.__check
_shamt
()
235 return Operator("<<", [self
, other
])
236 def __rlshift__(self
, other
):
238 return Operator("<<", [other
, self
])
239 def __rshift__(self
, other
):
240 other
= Value
.cast(other
)
241 other
.__check
_shamt
()
242 return Operator(">>", [self
, other
])
243 def __rrshift__(self
, other
):
245 return Operator(">>", [other
, self
])
247 def __and__(self
, other
):
248 return Operator("&", [self
, other
])
249 def __rand__(self
, other
):
250 return Operator("&", [other
, self
])
251 def __xor__(self
, other
):
252 return Operator("^", [self
, other
])
253 def __rxor__(self
, other
):
254 return Operator("^", [other
, self
])
255 def __or__(self
, other
):
256 return Operator("|", [self
, other
])
257 def __ror__(self
, other
):
258 return Operator("|", [other
, self
])
260 def __eq__(self
, other
):
261 return Operator("==", [self
, other
])
262 def __ne__(self
, other
):
263 return Operator("!=", [self
, other
])
264 def __lt__(self
, other
):
265 return Operator("<", [self
, other
])
266 def __le__(self
, other
):
267 return Operator("<=", [self
, other
])
268 def __gt__(self
, other
):
269 return Operator(">", [self
, other
])
270 def __ge__(self
, other
):
271 return Operator(">=", [self
, other
])
274 width
, signed
= self
.shape()
276 return Mux(self
>= 0, self
, -self
)
281 return self
.shape().width
283 def __getitem__(self
, key
):
285 if isinstance(key
, int):
286 if key
not in range(-n
, n
):
287 raise IndexError(f
"Index {key} is out of bounds for a {n}-bit value")
290 return Slice(self
, key
, key
+ 1)
291 elif isinstance(key
, slice):
292 start
, stop
, step
= key
.indices(n
)
294 return Cat(self
[i
] for i
in range(start
, stop
, step
))
295 return Slice(self
, start
, stop
)
297 raise TypeError("Cannot index value with {}".format(repr(key
)))
299 def as_unsigned(self
):
300 """Conversion to unsigned.
305 This ``Value`` reinterpreted as a unsigned integer.
307 return Operator("u", [self
])
310 """Conversion to signed.
315 This ``Value`` reinterpreted as a signed integer.
317 return Operator("s", [self
])
320 """Conversion to boolean.
325 ``1`` if any bits are set, ``0`` otherwise.
327 return Operator("b", [self
])
330 """Check if any bits are ``1``.
335 ``1`` if any bits are set, ``0`` otherwise.
337 return Operator("r|", [self
])
340 """Check if all bits are ``1``.
345 ``1`` if all bits are set, ``0`` otherwise.
347 return Operator("r&", [self
])
350 """Compute pairwise exclusive-or of every bit.
355 ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set.
357 return Operator("r^", [self
])
359 def implies(premise
, conclusion
):
365 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
367 return ~premise | conclusion
369 def bit_select(self
, offset
, width
):
370 """Part-select with bit granularity.
372 Selects a constant width but variable offset part of a ``Value``, such that successive
373 parts overlap by all but 1 bit.
378 Index of first selected bit.
380 Number of selected bits.
385 Selected part of the ``Value``
387 offset
= Value
.cast(offset
)
388 if type(offset
) is Const
and isinstance(width
, int):
389 return self
[offset
.value
:offset
.value
+ width
]
390 return Part(self
, offset
, width
, stride
=1, src_loc_at
=1)
392 def word_select(self
, offset
, width
):
393 """Part-select with word granularity.
395 Selects a constant width but variable offset part of a ``Value``, such that successive
396 parts do not overlap.
401 Index of first selected word.
403 Number of selected bits.
408 Selected part of the ``Value``
410 offset
= Value
.cast(offset
)
411 if type(offset
) is Const
and isinstance(width
, int):
412 return self
[offset
.value
* width
:(offset
.value
+ 1) * width
]
413 return Part(self
, offset
, width
, stride
=width
, src_loc_at
=1)
415 def matches(self
, *patterns
):
418 Matches against a set of patterns, which may be integers or bit strings, recognizing
419 the same grammar as ``Case()``.
423 patterns : int or str
424 Patterns to match against.
429 ``1`` if any pattern matches the value, ``0`` otherwise.
432 for pattern
in patterns
:
433 if not isinstance(pattern
, (int, str, Enum
)):
434 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
437 if isinstance(pattern
, str) and any(bit
not in "01- \t" for bit
in pattern
):
438 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
439 "bits, and may include whitespace"
441 if (isinstance(pattern
, str) and
442 len("".join(pattern
.split())) != len(self
)):
443 raise SyntaxError("Match pattern '{}' must have the same width as match value "
445 .format(pattern
, len(self
)))
446 if isinstance(pattern
, int) and bits_for(pattern
) > len(self
):
447 warnings
.warn("Match pattern '{:b}' is wider than match value "
448 "(which has width {}); comparison will never be true"
449 .format(pattern
, len(self
)),
450 SyntaxWarning, stacklevel
=3)
452 if isinstance(pattern
, str):
453 pattern
= "".join(pattern
.split()) # remove whitespace
454 mask
= int(pattern
.replace("0", "1").replace("-", "0"), 2)
455 pattern
= int(pattern
.replace("-", "0"), 2)
456 matches
.append((self
& mask
) == pattern
)
457 elif isinstance(pattern
, int):
458 matches
.append(self
== pattern
)
459 elif isinstance(pattern
, Enum
):
460 matches
.append(self
== pattern
.value
)
465 elif len(matches
) == 1:
468 return Cat(*matches
).any()
470 def shift_left(self
, amount
):
471 """Shift left by constant amount.
481 If the amount is positive, the input shifted left. Otherwise, the input shifted right.
483 if not isinstance(amount
, int):
484 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
486 return self
.shift_right(-amount
)
487 if self
.shape().signed
:
488 return Cat(Const(0, amount
), self
).as_signed()
490 return Cat(Const(0, amount
), self
) # unsigned
492 def shift_right(self
, amount
):
493 """Shift right by constant amount.
503 If the amount is positive, the input shifted right. Otherwise, the input shifted left.
505 if not isinstance(amount
, int):
506 raise TypeError("Shift amount must be an integer, not {!r}".format(amount
))
508 return self
.shift_left(-amount
)
509 if self
.shape().signed
:
510 return self
[amount
:].as_signed()
512 return self
[amount
:] # unsigned
514 def rotate_left(self
, amount
):
515 """Rotate left by constant amount.
525 If the amount is positive, the input rotated left. Otherwise, the input rotated right.
527 if not isinstance(amount
, int):
528 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
530 return Cat(self
[-amount
:], self
[:-amount
]) # meow :3
532 def rotate_right(self
, amount
):
533 """Rotate right by constant amount.
543 If the amount is positive, the input rotated right. Otherwise, the input rotated right.
545 if not isinstance(amount
, int):
546 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount
))
548 return Cat(self
[amount
:], self
[:amount
])
556 Value to be assigned.
561 Assignment statement that can be used in combinatorial or synchronous context.
563 return Assign(self
, value
, src_loc_at
=1)
567 """Bit width and signedness of a value.
576 >>> Signal(8).shape()
577 Shape(width=8, signed=False)
578 >>> Const(0xaa).shape()
579 Shape(width=8, signed=False)
583 def _lhs_signals(self
):
584 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
587 def _rhs_signals(self
):
591 raise TypeError("Value {!r} cannot be evaluated as constant".format(self
))
598 """A constant, literal integer value.
603 shape : int or tuple or None
604 Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
605 in this constant and whether it is signed (can represent negative values).
606 ``shape`` defaults to the minimum possible width and signedness of ``value``.
616 def normalize(value
, shape
):
617 width
, signed
= shape
618 mask
= (1 << width
) - 1
620 if signed
and value
>> (width
- 1):
624 def __init__(self
, value
, shape
=None, *, src_loc_at
=0):
625 # We deliberately do not call Value.__init__ here.
626 self
.value
= int(value
)
628 shape
= Shape(bits_for(self
.value
), signed
=self
.value
< 0)
629 elif isinstance(shape
, int):
630 shape
= Shape(shape
, signed
=self
.value
< 0)
632 shape
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
633 self
.width
, self
.signed
= shape
634 self
.value
= self
.normalize(self
.value
, shape
)
637 return Shape(self
.width
, self
.signed
)
639 def _rhs_signals(self
):
646 return "(const {}'{}d{})".format(self
.width
, "s" if self
.signed
else "", self
.value
)
649 C
= Const
# shorthand
652 class AnyValue(Value
, DUID
):
653 def __init__(self
, shape
, *, src_loc_at
=0):
654 super().__init
__(src_loc_at
=src_loc_at
)
655 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
656 if not isinstance(self
.width
, int) or self
.width
< 0:
657 raise TypeError("Width must be a non-negative integer, not {!r}"
661 return Shape(self
.width
, self
.signed
)
663 def _rhs_signals(self
):
668 class AnyConst(AnyValue
):
670 return "(anyconst {}'{})".format(self
.width
, "s" if self
.signed
else "")
674 class AnySeq(AnyValue
):
676 return "(anyseq {}'{})".format(self
.width
, "s" if self
.signed
else "")
680 class Operator(Value
):
681 def __init__(self
, operator
, operands
, *, src_loc_at
=0):
682 super().__init
__(src_loc_at
=1 + src_loc_at
)
683 self
.operator
= operator
684 self
.operands
= [Value
.cast(op
) for op
in operands
]
687 def _bitwise_binary_shape(a_shape
, b_shape
):
688 a_bits
, a_sign
= a_shape
689 b_bits
, b_sign
= b_shape
690 if not a_sign
and not b_sign
:
691 # both operands unsigned
692 return Shape(max(a_bits
, b_bits
), False)
693 elif a_sign
and b_sign
:
694 # both operands signed
695 return Shape(max(a_bits
, b_bits
), True)
696 elif not a_sign
and b_sign
:
697 # first operand unsigned (add sign bit), second operand signed
698 return Shape(max(a_bits
+ 1, b_bits
), True)
700 # first signed, second operand unsigned (add sign bit)
701 return Shape(max(a_bits
, b_bits
+ 1), True)
703 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
704 if len(op_shapes
) == 1:
705 (a_width
, a_signed
), = op_shapes
706 if self
.operator
in ("+", "~"):
707 return Shape(a_width
, a_signed
)
708 if self
.operator
== "-":
709 return Shape(a_width
+ 1, True)
710 if self
.operator
in ("b", "r|", "r&", "r^"):
711 return Shape(1, False)
712 if self
.operator
== "u":
713 return Shape(a_width
, False)
714 if self
.operator
== "s":
715 return Shape(a_width
, True)
716 elif len(op_shapes
) == 2:
717 (a_width
, a_signed
), (b_width
, b_signed
) = op_shapes
718 if self
.operator
in ("+", "-"):
719 width
, signed
= _bitwise_binary_shape(*op_shapes
)
720 return Shape(width
+ 1, signed
)
721 if self
.operator
== "*":
722 return Shape(a_width
+ b_width
, a_signed
or b_signed
)
723 if self
.operator
in ("//", "%"):
725 return Shape(a_width
, a_signed
)
726 if self
.operator
in ("<", "<=", "==", "!=", ">", ">="):
727 return Shape(1, False)
728 if self
.operator
in ("&", "^", "|"):
729 return _bitwise_binary_shape(*op_shapes
)
730 if self
.operator
== "<<":
732 return Shape(a_width
+ 2 ** b_width
- 1, a_signed
)
733 if self
.operator
== ">>":
735 return Shape(a_width
, a_signed
)
736 elif len(op_shapes
) == 3:
737 if self
.operator
== "m":
738 s_shape
, a_shape
, b_shape
= op_shapes
739 return _bitwise_binary_shape(a_shape
, b_shape
)
740 raise NotImplementedError("Operator {}/{} not implemented"
741 .format(self
.operator
, len(op_shapes
))) # :nocov:
743 def _rhs_signals(self
):
744 return union(op
._rhs
_signals
() for op
in self
.operands
)
747 return "({} {})".format(self
.operator
, " ".join(map(repr, self
.operands
)))
750 def Mux(sel
, val1
, val0
):
751 if isinstance(sel
, bool): # one instance where Mux is passed an actual bool
752 sel
= Value
.cast(sel
)
753 return sel
.__Mux
__(val1
, val0
)
756 def _InternalMux(sel
, val1
, val0
):
757 """Choose between two values.
770 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
772 return Operator("m", [sel
, val1
, val0
])
777 def __init__(self
, value
, start
, stop
, *, src_loc_at
=0):
778 if not isinstance(start
, int):
779 raise TypeError("Slice start must be an integer, not {!r}".format(start
))
780 if not isinstance(stop
, int):
781 raise TypeError("Slice stop must be an integer, not {!r}".format(stop
))
784 if start
not in range(-(n
+1), n
+1):
785 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
788 if stop
not in range(-(n
+1), n
+1):
789 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop
, n
))
793 raise IndexError("Slice start {} must be less than slice stop {}".format(start
, stop
))
795 super().__init
__(src_loc_at
=src_loc_at
)
796 self
.value
= Value
.cast(value
)
797 self
.start
= int(start
)
798 self
.stop
= int(stop
)
801 return Shape(self
.stop
- self
.start
)
803 def _lhs_signals(self
):
804 return self
.value
._lhs
_signals
()
806 def _rhs_signals(self
):
807 return self
.value
._rhs
_signals
()
810 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.stop
)
814 def Part(value
, offset
, width
, stride
=1, *, src_loc_at
=0):
815 return value
.__Part
__(offset
, width
, stride
, src_loc_at
=src_loc_at
)
818 class _InternalPart(Value
):
819 def __init__(self
, value
, offset
, width
, stride
=1, *, src_loc_at
=0):
820 if not isinstance(width
, int) or width
< 0:
821 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width
))
822 if not isinstance(stride
, int) or stride
<= 0:
823 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride
))
825 super().__init
__(src_loc_at
=src_loc_at
)
827 self
.offset
= Value
.cast(offset
)
832 return Shape(self
.width
)
834 def _lhs_signals(self
):
835 return self
.value
._lhs
_signals
()
837 def _rhs_signals(self
):
838 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
841 return "(part {} {} {} {})".format(repr(self
.value
), repr(self
.offset
),
842 self
.width
, self
.stride
)
846 def Cat(*args
, src_loc_at
=0):
847 """Concatenate values.
849 Behaviour is required to be identical to _InternalCat.
850 The first argument "defines" the way that all others are
851 handled. If the first argument is derived from UserValue,
852 it is not downcast to a type Value because doing so would
853 lose the opportunity for "redirection" (Value.__Cat__ would
856 # flatten the args and convert to tuple (not a generator)
857 args
= tuple(flatten(args
))
858 # check if there are no arguments (zero-length Signal).
860 return _InternalCat(*args
, src_loc_at
=src_loc_at
)
861 # determine if the first is a UserValue.
862 first
, rest
= args
[0], args
[1:]
863 if not isinstance(args
[0], UserValue
):
864 first
= Value
.cast(first
) # ok to downcast to Value
865 # all other arguments are safe to downcast to Value
866 rest
= map(Value
.cast
, rest
)
867 # assume first item defines the "handling" for all others
868 return first
.__Cat
__(*rest
, src_loc_at
=src_loc_at
)
871 class _InternalCat(Value
):
872 """Concatenate values.
874 Form a compound ``Value`` from several smaller ones by concatenation.
875 The first argument occupies the lower bits of the result.
876 The return value can be used on either side of an assignment, that
877 is, the concatenated value can be used as an argument on the RHS or
878 as a target on the LHS. If it is used on the LHS, it must solely
879 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
880 meeting these properties. The bit length of the return value is the sum of
881 the bit lengths of the arguments::
883 len(Cat(args)) == sum(len(arg) for arg in args)
887 *args : Values or iterables of Values, inout
888 ``Value`` s to be concatenated.
893 Resulting ``Value`` obtained by concatentation.
895 def __init__(self
, *args
, src_loc_at
=0):
896 super().__init
__(src_loc_at
=src_loc_at
)
897 self
.parts
= [Value
.cast(v
) for v
in flatten(args
)]
900 return Shape(sum(len(part
) for part
in self
.parts
))
902 def _lhs_signals(self
):
903 return union((part
._lhs
_signals
() for part
in self
.parts
), start
=SignalSet())
905 def _rhs_signals(self
):
906 return union((part
._rhs
_signals
() for part
in self
.parts
), start
=SignalSet())
910 for part
in reversed(self
.parts
):
912 value |
= part
._as
_const
()
916 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
920 def Repl(value
, count
, *, src_loc_at
=0):
921 if not isinstance(value
, Value
): # rare instances where integers are passed
922 value
= Value
.cast(value
)
923 return value
.__Repl
__(count
, src_loc_at
=src_loc_at
)
926 class _InternalRepl(Value
):
929 An input value is replicated (repeated) several times
930 to be used on the RHS of assignments::
932 len(Repl(s, n)) == len(s) * n
937 Input value to be replicated.
939 Number of replications.
946 def __init__(self
, value
, count
, *, src_loc_at
=0):
947 if not isinstance(count
, int) or count
< 0:
948 raise TypeError("Replication count must be a non-negative integer, not {!r}"
951 super().__init
__(src_loc_at
=src_loc_at
)
952 self
.value
= Value
.cast(value
)
956 return Shape(len(self
.value
) * self
.count
)
958 def _rhs_signals(self
):
959 return self
.value
._rhs
_signals
()
962 return "(repl {!r} {})".format(self
.value
, self
.count
)
966 class Signal(Value
, DUID
):
967 """A varying integer value.
971 shape : ``Shape``-castable object or None
972 Specification for the number of bits in this ``Signal`` and its signedness (whether it
973 can represent negative values). See ``Shape.cast`` for details.
974 If not specified, ``shape`` defaults to 1-bit and non-signed.
976 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
977 name this ``Signal`` is assigned to.
978 reset : int or integral Enum
979 Reset (synchronous) or default (combinatorial) value.
980 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
981 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
982 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
983 assumes its ``reset`` value. Defaults to 0.
985 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
986 The ``reset`` value is only used as a combinatorial default or as the initial value.
987 Defaults to ``False``.
989 Dictionary of synthesis attributes.
990 decoder : function or Enum
991 A function converting integer signal values to human-readable strings (e.g. FSM state
992 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
993 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
1007 def __init__(self
, shape
=None, *, name
=None, reset
=0, reset_less
=False,
1008 attrs
=None, decoder
=None, src_loc_at
=0):
1009 super().__init
__(src_loc_at
=src_loc_at
)
1011 if name
is not None and not isinstance(name
, str):
1012 raise TypeError("Name must be a string, not {!r}".format(name
))
1013 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$signal")
1017 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
1019 if isinstance(reset
, Enum
):
1021 if not isinstance(reset
, int):
1022 raise TypeError("Reset value has to be an int or an integral Enum")
1024 reset_width
= bits_for(reset
, self
.signed
)
1025 if reset
!= 0 and reset_width
> self
.width
:
1026 warnings
.warn("Reset value {!r} requires {} bits to represent, but the signal "
1028 .format(reset
, reset_width
, self
.width
),
1029 SyntaxWarning, stacklevel
=2 + src_loc_at
)
1032 self
.reset_less
= bool(reset_less
)
1034 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
1036 if decoder
is None and isinstance(shape
, type) and issubclass(shape
, Enum
):
1038 if isinstance(decoder
, type) and issubclass(decoder
, Enum
):
1039 def enum_decoder(value
):
1041 return "{0.name:}/{0.value:}".format(decoder(value
))
1044 self
.decoder
= enum_decoder
1045 self
._enum
_class
= decoder
1047 self
.decoder
= decoder
1048 self
._enum
_class
= None
1050 # Not a @classmethod because nmigen.compat requires it.
1052 def like(other
, *, name
=None, name_suffix
=None, src_loc_at
=0, **kwargs
):
1053 """Create Signal based on another.
1058 Object to base this Signal on.
1060 if name
is not None:
1061 new_name
= str(name
)
1062 elif name_suffix
is not None:
1063 new_name
= other
.name
+ str(name_suffix
)
1065 new_name
= tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$like")
1066 kw
= dict(shape
=Value
.cast(other
).shape(), name
=new_name
)
1067 if isinstance(other
, Signal
):
1068 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
1069 attrs
=other
.attrs
, decoder
=other
.decoder
)
1071 return Signal(**kw
, src_loc_at
=1 + src_loc_at
)
1074 return Shape(self
.width
, self
.signed
)
1076 def _lhs_signals(self
):
1077 return SignalSet((self
,))
1079 def _rhs_signals(self
):
1080 return SignalSet((self
,))
1083 return "(sig {})".format(self
.name
)
1087 class ClockSignal(Value
):
1088 """Clock signal for a clock domain.
1090 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
1091 All of these signals ultimately refer to the same signal, but they can be manipulated
1092 independently of the clock domain, even before the clock domain is created.
1097 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
1099 def __init__(self
, domain
="sync", *, src_loc_at
=0):
1100 super().__init
__(src_loc_at
=src_loc_at
)
1101 if not isinstance(domain
, str):
1102 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1103 if domain
== "comb":
1104 raise ValueError("Domain '{}' does not have a clock".format(domain
))
1105 self
.domain
= domain
1110 def _lhs_signals(self
):
1111 return SignalSet((self
,))
1113 def _rhs_signals(self
):
1114 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
1117 return "(clk {})".format(self
.domain
)
1121 class ResetSignal(Value
):
1122 """Reset signal for a clock domain.
1124 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
1125 All of these signals ultimately refer to the same signal, but they can be manipulated
1126 independently of the clock domain, even before the clock domain is created.
1131 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
1132 allow_reset_less : bool
1133 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
1135 def __init__(self
, domain
="sync", allow_reset_less
=False, *, src_loc_at
=0):
1136 super().__init
__(src_loc_at
=src_loc_at
)
1137 if not isinstance(domain
, str):
1138 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
1139 if domain
== "comb":
1140 raise ValueError("Domain '{}' does not have a reset".format(domain
))
1141 self
.domain
= domain
1142 self
.allow_reset_less
= allow_reset_less
1147 def _lhs_signals(self
):
1148 return SignalSet((self
,))
1150 def _rhs_signals(self
):
1151 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
1154 return "(rst {})".format(self
.domain
)
1157 class Array(MutableSequence
):
1158 """Addressable multiplexer.
1160 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
1163 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
1164 assignments, provided that all elements of the array are values. The array proxy also supports
1165 attribute access and further indexing, each returning another array proxy; this means that
1166 the results of indexing into arrays, arrays of records, and arrays of arrays can all
1167 be used as first-class values.
1169 It is an error to change an array or any of its elements after an array proxy was created.
1170 Changing the array directly will raise an exception. However, it is not possible to detect
1171 the elements being modified; if an element's attribute or element is modified after the proxy
1172 for it has been created, the proxy will refer to stale data.
1179 gpios = Array(Signal() for _ in range(10))
1181 m.d.sync += gpios[bus.addr].eq(bus.w_data)
1183 m.d.sync += bus.r_data.eq(gpios[bus.addr])
1185 Multidimensional array::
1187 mult = Array(Array(x * y for y in range(10)) for x in range(10))
1188 a = Signal.range(10)
1189 b = Signal.range(10)
1191 m.d.comb += r.eq(mult[a][b])
1199 buses = Array(Record(layout) for busno in range(4))
1200 master = Record(layout)
1202 buses[sel].r_en.eq(master.r_en),
1203 master.r_data.eq(buses[sel].r_data),
1206 def __init__(self
, iterable
=()):
1207 self
._inner
= list(iterable
)
1208 self
._proxy
_at
= None
1209 self
._mutable
= True
1211 def __getitem__(self
, index
):
1212 if isinstance(index
, Value
):
1214 self
._proxy
_at
= tracer
.get_src_loc()
1215 self
._mutable
= False
1216 return ArrayProxy(self
, index
)
1218 return self
._inner
[index
]
1221 return len(self
._inner
)
1223 def _check_mutability(self
):
1224 if not self
._mutable
:
1225 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1226 "at {}:{}".format(*self
._proxy
_at
))
1228 def __setitem__(self
, index
, value
):
1229 self
._check
_mutability
()
1230 self
._inner
[index
] = value
1232 def __delitem__(self
, index
):
1233 self
._check
_mutability
()
1234 del self
._inner
[index
]
1236 def insert(self
, index
, value
):
1237 self
._check
_mutability
()
1238 self
._inner
.insert(index
, value
)
1241 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
1242 ", ".join(map(repr, self
._inner
)))
1246 class ArrayProxy(Value
):
1247 def __init__(self
, elems
, index
, *, src_loc_at
=0):
1248 super().__init
__(src_loc_at
=1 + src_loc_at
)
1250 self
.index
= Value
.cast(index
)
1252 def __getattr__(self
, attr
):
1253 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
1255 def __getitem__(self
, index
):
1256 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
1258 def _iter_as_values(self
):
1259 return (Value
.cast(elem
) for elem
in self
.elems
)
1262 unsigned_width
= signed_width
= 0
1263 has_unsigned
= has_signed
= False
1264 for elem_width
, elem_signed
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
1267 signed_width
= max(signed_width
, elem_width
)
1270 unsigned_width
= max(unsigned_width
, elem_width
)
1271 # The shape of the proxy must be such that it preserves the mathematical value of the array
1272 # elements. I.e., shape-wise, an array proxy must be identical to an equivalent mux tree.
1273 # To ensure this holds, if the array contains both signed and unsigned values, make sure
1274 # that every unsigned value is zero-extended by at least one bit.
1275 if has_signed
and has_unsigned
and unsigned_width
>= signed_width
:
1276 # Array contains both signed and unsigned values, and at least one of the unsigned
1277 # values won't be zero-extended otherwise.
1278 return signed(unsigned_width
+ 1)
1280 # Array contains values of the same signedness, or else all of the unsigned values
1281 # are zero-extended.
1282 return Shape(max(unsigned_width
, signed_width
), has_signed
)
1284 def _lhs_signals(self
):
1285 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()),
1289 def _rhs_signals(self
):
1290 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()),
1292 return self
.index
._rhs
_signals
() | signals
1295 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
1298 # TODO(nmigen-0.4): remove
1299 class UserValue(Value
):
1300 """Value with custom lowering.
1302 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1303 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1304 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1305 value when required.
1307 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1308 nMigen's view of representation of all values stays internally consistent. If the class
1309 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1310 it is not mutated in a way that changes its representation.
1312 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1313 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1314 * Querying the shape using ``.shape()`` or ``len()``;
1315 * Creating a similarly shaped signal using ``Signal.like``;
1316 * Indexing or iterating through individual bits;
1317 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1319 @deprecated("instead of `UserValue`, use `ValueCastable`", stacklevel
=3)
1320 def __init__(self
, *, src_loc_at
=0):
1321 super().__init
__(src_loc_at
=1 + src_loc_at
)
1322 self
.__lowered
= None
1326 """Conversion to a concrete representation."""
1329 def _lazy_lower(self
):
1330 if self
.__lowered
is None:
1331 lowered
= self
.lower()
1332 if isinstance(lowered
, UserValue
):
1333 lowered
= lowered
._lazy
_lower
()
1334 self
.__lowered
= Value
.cast(lowered
)
1335 return self
.__lowered
1338 return self
._lazy
_lower
().shape()
1340 def _lhs_signals(self
):
1341 return self
._lazy
_lower
()._lhs
_signals
()
1343 def _rhs_signals(self
):
1344 return self
._lazy
_lower
()._rhs
_signals
()
1347 class ValueCastable
:
1348 """Base class for classes which can be cast to Values.
1350 A ``ValueCastable`` can be cast to ``Value``, meaning its precise representation does not have
1351 to be immediately known. This is useful in certain metaprogramming scenarios. Instead of
1352 providing fixed semantics upfront, it is kept abstract for as long as possible, only being
1353 cast to a concrete nMigen value when required.
1355 Note that it is necessary to ensure that nMigen's view of representation of all values stays
1356 internally consistent. The class deriving from ``ValueCastable`` must decorate the ``as_value``
1357 method with the ``lowermethod`` decorator, which ensures that all calls to ``as_value`` return
1358 the same ``Value`` representation. If the class deriving from ``ValueCastable`` is mutable,
1359 it is up to the user to ensure that it is not mutated in a way that changes its representation
1360 after the first call to ``as_value``.
1362 def __new__(cls
, *args
, **kwargs
):
1363 self
= super().__new
__(cls
)
1364 if not hasattr(self
, "as_value"):
1365 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must override "
1366 "the `as_value` method")
1368 if not hasattr(self
.as_value
, "_ValueCastable__memoized"):
1369 raise TypeError(f
"Class '{cls.__name__}' deriving from `ValueCastable` must decorate "
1370 "the `as_value` method with the `ValueCastable.lowermethod` decorator")
1374 def lowermethod(func
):
1375 """Decorator to memoize lowering methods.
1377 Ensures the decorated method is called only once, with subsequent method calls returning the
1378 object returned by the first first method call.
1380 This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` subclasses.
1381 This is to ensure that nMigen's view of representation of all values stays internally
1384 @functools.wraps(func
)
1385 def wrapper_memoized(self
, *args
, **kwargs
):
1386 if not hasattr(self
, "_ValueCastable__lowered_to"):
1387 self
.__lowered
_to
= func(self
, *args
, **kwargs
)
1388 return self
.__lowered
_to
1389 wrapper_memoized
.__memoized
= True
1390 return wrapper_memoized
1394 class Sample(Value
):
1395 """Value from the past.
1397 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1398 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1399 to the value of the expression calculated as if each signal had its reset value.
1401 def __init__(self
, expr
, clocks
, domain
, *, src_loc_at
=0):
1402 super().__init
__(src_loc_at
=1 + src_loc_at
)
1403 self
.value
= Value
.cast(expr
)
1404 self
.clocks
= int(clocks
)
1405 self
.domain
= domain
1406 if not isinstance(self
.value
, (Const
, Signal
, ClockSignal
, ResetSignal
, Initial
)):
1407 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1408 .format(self
.value
))
1410 raise ValueError("Cannot sample a value {} cycles in the future"
1411 .format(-self
.clocks
))
1412 if not (self
.domain
is None or isinstance(self
.domain
, str)):
1413 raise TypeError("Domain name must be a string or None, not {!r}"
1414 .format(self
.domain
))
1417 return self
.value
.shape()
1419 def _rhs_signals(self
):
1420 return SignalSet((self
,))
1423 return "(sample {!r} @ {}[{}])".format(
1424 self
.value
, "<default>" if self
.domain
is None else self
.domain
, self
.clocks
)
1427 def Past(expr
, clocks
=1, domain
=None):
1428 return Sample(expr
, clocks
, domain
)
1431 def Stable(expr
, clocks
=0, domain
=None):
1432 return Sample(expr
, clocks
+ 1, domain
) == Sample(expr
, clocks
, domain
)
1435 def Rose(expr
, clocks
=0, domain
=None):
1436 return ~
Sample(expr
, clocks
+ 1, domain
) & Sample(expr
, clocks
, domain
)
1439 def Fell(expr
, clocks
=0, domain
=None):
1440 return Sample(expr
, clocks
+ 1, domain
) & ~
Sample(expr
, clocks
, domain
)
1444 class Initial(Value
):
1445 """Start indicator, for model checking.
1447 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1449 def __init__(self
, *, src_loc_at
=0):
1450 super().__init
__(src_loc_at
=src_loc_at
)
1455 def _rhs_signals(self
):
1456 return SignalSet((self
,))
1462 class _StatementList(list):
1464 return "({})".format(" ".join(map(repr, self
)))
1468 def __init__(self
, *, src_loc_at
=0):
1469 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
1473 if isinstance(obj
, Iterable
):
1474 return _StatementList(list(chain
.from_iterable(map(Statement
.cast
, obj
))))
1476 if isinstance(obj
, Statement
):
1477 return _StatementList([obj
])
1479 raise TypeError("Object {!r} is not an nMigen statement".format(obj
))
1483 def Assign(lhs
, rhs
, *, src_loc_at
=0):
1484 return lhs
.__Assign
__(rhs
, src_loc_at
=src_loc_at
)
1487 class _InternalAssign(Statement
):
1488 def __init__(self
, lhs
, rhs
, *, src_loc_at
=0):
1489 super().__init
__(src_loc_at
=src_loc_at
)
1490 self
.lhs
= Value
.cast(lhs
)
1491 self
.rhs
= Value
.cast(rhs
)
1493 def _lhs_signals(self
):
1494 return self
.lhs
._lhs
_signals
()
1496 def _rhs_signals(self
):
1497 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
1500 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
1503 class UnusedProperty(UnusedMustUse
):
1507 class Property(Statement
, MustUse
):
1508 _MustUse__warning
= UnusedProperty
1510 def __init__(self
, test
, *, _check
=None, _en
=None, src_loc_at
=0):
1511 super().__init
__(src_loc_at
=src_loc_at
)
1512 self
.test
= Value
.cast(test
)
1513 self
._check
= _check
1515 if self
._check
is None:
1516 self
._check
= Signal(reset_less
=True, name
="${}$check".format(self
._kind
))
1517 self
._check
.src_loc
= self
.src_loc
1519 self
._en
= Signal(reset_less
=True, name
="${}$en".format(self
._kind
))
1520 self
._en
.src_loc
= self
.src_loc
1522 def _lhs_signals(self
):
1523 return SignalSet((self
._en
, self
._check
))
1525 def _rhs_signals(self
):
1526 return self
.test
._rhs
_signals
()
1529 return "({} {!r})".format(self
._kind
, self
.test
)
1533 class Assert(Property
):
1538 class Assume(Property
):
1543 class Cover(Property
):
1548 def Switch(test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1549 return test
.__Switch
__(cases
, src_loc
=src_loc
, src_loc_at
=src_loc_at
,
1550 case_src_locs
=case_src_locs
)
1553 class _InternalSwitch(Statement
):
1554 def __init__(self
, test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1556 super().__init
__(src_loc_at
=src_loc_at
)
1558 # Switch is a bit special in terms of location tracking because it is usually created
1559 # long after the control has left the statement that directly caused its creation.
1560 self
.src_loc
= src_loc
1561 # Switch is also a bit special in that its parts also have location information. It can't
1562 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1563 self
.case_src_locs
= {}
1565 self
.test
= Value
.cast(test
)
1566 self
.cases
= OrderedDict()
1567 for orig_keys
, stmts
in cases
.items():
1568 # Map: None -> (); key -> (key,); (key...) -> (key...)
1572 if not isinstance(keys
, tuple):
1574 # Map: 2 -> "0010"; "0010" -> "0010"
1576 key_mask
= (1 << len(self
.test
)) - 1
1578 if isinstance(key
, str):
1579 key
= "".join(key
.split()) # remove whitespace
1580 elif isinstance(key
, int):
1581 key
= format(key
& key_mask
, "b").rjust(len(self
.test
), "0")
1582 elif isinstance(key
, Enum
):
1583 key
= format(key
.value
& key_mask
, "b").rjust(len(self
.test
), "0")
1585 raise TypeError("Object {!r} cannot be used as a switch key"
1587 assert len(key
) == len(self
.test
)
1588 new_keys
= (*new_keys
, key
)
1589 if not isinstance(stmts
, Iterable
):
1591 self
.cases
[new_keys
] = Statement
.cast(stmts
)
1592 if orig_keys
in case_src_locs
:
1593 self
.case_src_locs
[new_keys
] = case_src_locs
[orig_keys
]
1595 def _lhs_signals(self
):
1596 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1600 def _rhs_signals(self
):
1601 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1603 return self
.test
._rhs
_signals
() | signals
1606 def case_repr(keys
, stmts
):
1607 stmts_repr
= " ".join(map(repr, stmts
))
1609 return "(default {})".format(stmts_repr
)
1610 elif len(keys
) == 1:
1611 return "(case {} {})".format(keys
[0], stmts_repr
)
1613 return "(case ({}) {})".format(" ".join(keys
), stmts_repr
)
1614 case_reprs
= [case_repr(keys
, stmts
) for keys
, stmts
in self
.cases
.items()]
1615 return "(switch {!r} {})".format(self
.test
, " ".join(case_reprs
))
1618 class _MappedKeyCollection(metaclass
=ABCMeta
):
1620 def _map_key(self
, key
):
1624 def _unmap_key(self
, key
):
1628 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
1629 def __init__(self
, pairs
=()):
1630 self
._storage
= OrderedDict()
1631 for key
, value
in pairs
:
1634 def __getitem__(self
, key
):
1635 key
= None if key
is None else self
._map
_key
(key
)
1636 return self
._storage
[key
]
1638 def __setitem__(self
, key
, value
):
1639 key
= None if key
is None else self
._map
_key
(key
)
1640 self
._storage
[key
] = value
1642 def __delitem__(self
, key
):
1643 key
= None if key
is None else self
._map
_key
(key
)
1644 del self
._storage
[key
]
1647 for key
in self
._storage
:
1651 yield self
._unmap
_key
(key
)
1653 def __eq__(self
, other
):
1654 if not isinstance(other
, type(self
)):
1656 if len(self
) != len(other
):
1658 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
1661 if self
._storage
[ak
] != other
._storage
[bk
]:
1666 return len(self
._storage
)
1669 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
1670 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
1674 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
1675 def __init__(self
, elements
=()):
1676 self
._storage
= OrderedDict()
1677 for elem
in elements
:
1680 def add(self
, value
):
1681 self
._storage
[self
._map
_key
(value
)] = None
1683 def update(self
, values
):
1684 for value
in values
:
1687 def discard(self
, value
):
1689 del self
._storage
[self
._map
_key
(value
)]
1691 def __contains__(self
, value
):
1692 return self
._map
_key
(value
) in self
._storage
1695 for key
in [k
for k
in self
._storage
]:
1696 yield self
._unmap
_key
(key
)
1699 return len(self
._storage
)
1702 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
1703 ", ".join(repr(x
) for x
in self
))
1707 def __init__(self
, value
):
1708 self
.value
= Value
.cast(value
)
1709 if isinstance(self
.value
, Const
):
1710 self
._hash
= hash(self
.value
.value
)
1711 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1712 self
._hash
= hash(self
.value
.duid
)
1713 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1714 self
._hash
= hash(self
.value
.domain
)
1715 elif isinstance(self
.value
, Operator
):
1716 self
._hash
= hash((self
.value
.operator
,
1717 tuple(ValueKey(o
) for o
in self
.value
.operands
)))
1718 elif isinstance(self
.value
, Slice
):
1719 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.stop
))
1720 elif isinstance(self
.value
, _InternalPart
):
1721 self
._hash
= hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
1722 self
.value
.width
, self
.value
.stride
))
1723 elif isinstance(self
.value
, _InternalCat
):
1724 self
._hash
= hash(tuple(ValueKey(o
) for o
in self
.value
.parts
))
1725 elif isinstance(self
.value
, ArrayProxy
):
1726 self
._hash
= hash((ValueKey(self
.value
.index
),
1727 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
1728 elif isinstance(self
.value
, Sample
):
1729 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.clocks
, 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
))
1739 def __eq__(self
, other
):
1740 if type(other
) is not ValueKey
:
1742 if type(self
.value
) is not type(other
.value
):
1745 if isinstance(self
.value
, Const
):
1746 return self
.value
.value
== other
.value
.value
1747 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1748 return self
.value
is other
.value
1749 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1750 return self
.value
.domain
== other
.value
.domain
1751 elif isinstance(self
.value
, Operator
):
1752 return (self
.value
.operator
== other
.value
.operator
and
1753 len(self
.value
.operands
) == len(other
.value
.operands
) and
1754 all(ValueKey(a
) == ValueKey(b
)
1755 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1756 elif isinstance(self
.value
, Slice
):
1757 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1758 self
.value
.start
== other
.value
.start
and
1759 self
.value
.stop
== other
.value
.stop
)
1760 elif isinstance(self
.value
, _InternalPart
):
1761 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1762 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1763 self
.value
.width
== other
.value
.width
and
1764 self
.value
.stride
== other
.value
.stride
)
1765 elif isinstance(self
.value
, _InternalCat
):
1766 return all(ValueKey(a
) == ValueKey(b
)
1767 for a
, b
in zip(self
.value
.parts
, other
.value
.parts
))
1768 elif isinstance(self
.value
, ArrayProxy
):
1769 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1770 len(self
.value
.elems
) == len(other
.value
.elems
) and
1771 all(ValueKey(a
) == ValueKey(b
)
1772 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1773 other
.value
._iter
_as
_values
())))
1774 elif isinstance(self
.value
, Sample
):
1775 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1776 self
.value
.clocks
== other
.value
.clocks
and
1777 self
.value
.domain
== self
.value
.domain
)
1778 elif isinstance(self
.value
, Initial
):
1781 raise TypeError("Object {!r} cannot be used as a key in value collections"
1782 .format(self
.value
))
1784 def __lt__(self
, other
):
1785 if not isinstance(other
, ValueKey
):
1787 if type(self
.value
) != type(other
.value
):
1790 if isinstance(self
.value
, Const
):
1791 return self
.value
< other
.value
1792 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1793 return self
.value
.duid
< other
.value
.duid
1794 elif isinstance(self
.value
, Slice
):
1795 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1796 self
.value
.start
< other
.value
.start
and
1797 self
.value
.end
< other
.value
.end
)
1799 raise TypeError("Object {!r} cannot be used as a key in value collections")
1802 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1805 class ValueDict(_MappedKeyDict
):
1807 _unmap_key
= lambda self
, key
: key
.value
1810 class ValueSet(_MappedKeySet
):
1812 _unmap_key
= lambda self
, key
: key
.value
1816 def __init__(self
, signal
):
1817 self
.signal
= signal
1818 if isinstance(signal
, Signal
):
1819 self
._intern
= (0, signal
.duid
)
1820 elif type(signal
) is ClockSignal
:
1821 self
._intern
= (1, signal
.domain
)
1822 elif type(signal
) is ResetSignal
:
1823 self
._intern
= (2, signal
.domain
)
1825 raise TypeError("Object {!r} is not an nMigen signal".format(signal
))
1828 return hash(self
._intern
)
1830 def __eq__(self
, other
):
1831 if type(other
) is not SignalKey
:
1833 return self
._intern
== other
._intern
1835 def __lt__(self
, other
):
1836 if type(other
) is not SignalKey
:
1837 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal
))
1838 return self
._intern
< other
._intern
1841 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1844 class SignalDict(_MappedKeyDict
):
1845 _map_key
= SignalKey
1846 _unmap_key
= lambda self
, key
: key
.signal
1849 class SignalSet(_MappedKeySet
):
1850 _map_key
= SignalKey
1851 _unmap_key
= lambda self
, key
: key
.signal