add redirection of __Mux__ to allow overrides for more advanced behaviour
[nmigen.git] / nmigen / hdl / ast.py
1 from abc import ABCMeta, abstractmethod
2 import warnings
3 import functools
4 from collections import OrderedDict
5 from collections.abc import Iterable, MutableMapping, MutableSet, MutableSequence
6 from enum import Enum
7 from itertools import chain
8
9 from .. import tracer
10 from .._utils import *
11 from .._unused import *
12
13
14 __all__ = [
15 "Shape", "signed", "unsigned",
16 "Value", "Const", "C", "AnyConst", "AnySeq", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
17 "Array", "ArrayProxy",
18 "Signal", "ClockSignal", "ResetSignal",
19 "UserValue", "ValueCastable",
20 "Sample", "Past", "Stable", "Rose", "Fell", "Initial",
21 "Statement", "Switch",
22 "Property", "Assign", "Assert", "Assume", "Cover",
23 "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "SignalSet",
24 ]
25
26
27 class DUID:
28 """Deterministic Unique IDentifier."""
29 __next_uid = 0
30 def __init__(self):
31 self.duid = DUID.__next_uid
32 DUID.__next_uid += 1
33
34
35 class Shape:
36 """Bit width and signedness of a value.
37
38 A ``Shape`` can be constructed using:
39 * explicit bit width and signedness;
40 * aliases :func:`signed` and :func:`unsigned`;
41 * casting from a variety of objects.
42
43 A ``Shape`` can be cast from:
44 * an integer, where the integer specifies the bit width;
45 * a range, where the result is wide enough to represent any element of the range, and is
46 signed if any element of the range is signed;
47 * an :class:`Enum` with all integer members or :class:`IntEnum`, where the result is wide
48 enough to represent any member of the enumeration, and is signed if any member of
49 the enumeration is signed.
50
51 Parameters
52 ----------
53 width : int
54 The number of bits in the representation, including the sign bit (if any).
55 signed : bool
56 If ``False``, the value is unsigned. If ``True``, the value is signed two's complement.
57 """
58 def __init__(self, width=1, signed=False):
59 if not isinstance(width, int) or width < 0:
60 raise TypeError("Width must be a non-negative integer, not {!r}"
61 .format(width))
62 self.width = width
63 self.signed = signed
64
65 def __iter__(self):
66 return iter((self.width, self.signed))
67
68 @staticmethod
69 def cast(obj, *, src_loc_at=0):
70 if isinstance(obj, Shape):
71 return obj
72 if isinstance(obj, int):
73 return Shape(obj)
74 if isinstance(obj, tuple):
75 width, signed = obj
76 warnings.warn("instead of `{tuple}`, use `{constructor}({width})`"
77 .format(constructor="signed" if signed else "unsigned", width=width,
78 tuple=obj),
79 DeprecationWarning, stacklevel=2 + src_loc_at)
80 return Shape(width, signed)
81 if isinstance(obj, range):
82 if len(obj) == 0:
83 return Shape(0, obj.start < 0)
84 signed = obj.start < 0 or (obj.stop - obj.step) < 0
85 width = max(bits_for(obj.start, signed),
86 bits_for(obj.stop - obj.step, signed))
87 return Shape(width, signed)
88 if isinstance(obj, type) and issubclass(obj, Enum):
89 min_value = min(member.value for member in obj)
90 max_value = max(member.value for member in obj)
91 if not isinstance(min_value, int) or not isinstance(max_value, int):
92 raise TypeError("Only enumerations with integer values can be used "
93 "as value shapes")
94 signed = min_value < 0 or max_value < 0
95 width = max(bits_for(min_value, signed), bits_for(max_value, signed))
96 return Shape(width, signed)
97 raise TypeError("Object {!r} cannot be used as value shape".format(obj))
98
99 def __repr__(self):
100 if self.signed:
101 return "signed({})".format(self.width)
102 else:
103 return "unsigned({})".format(self.width)
104
105 def __eq__(self, other):
106 if isinstance(other, tuple) and len(other) == 2:
107 width, signed = other
108 if isinstance(width, int) and isinstance(signed, bool):
109 return self.width == width and self.signed == signed
110 else:
111 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
112 "not {!r}"
113 .format(other))
114 if not isinstance(other, Shape):
115 raise TypeError("Shapes may be compared with other Shapes and (int, bool) tuples, "
116 "not {!r}"
117 .format(other))
118 return self.width == other.width and self.signed == other.signed
119
120
121 def unsigned(width):
122 """Shorthand for ``Shape(width, signed=False)``."""
123 return Shape(width, signed=False)
124
125
126 def signed(width):
127 """Shorthand for ``Shape(width, signed=True)``."""
128 return Shape(width, signed=True)
129
130
131 class Value(metaclass=ABCMeta):
132 @staticmethod
133 def cast(obj):
134 """Converts ``obj`` to an nMigen value.
135
136 Booleans and integers are wrapped into a :class:`Const`. Enumerations whose members are
137 all integers are converted to a :class:`Const` with a shape that fits every member.
138 """
139 if isinstance(obj, Value):
140 return obj
141 if isinstance(obj, int):
142 return Const(obj)
143 if isinstance(obj, Enum):
144 return Const(obj.value, Shape.cast(type(obj)))
145 if isinstance(obj, ValueCastable):
146 return obj.as_value()
147 raise TypeError("Object {!r} cannot be converted to an nMigen value".format(obj))
148
149 def __init__(self, *, src_loc_at=0):
150 super().__init__()
151 self.src_loc = tracer.get_src_loc(1 + src_loc_at)
152
153 def __Mux__(self, val1, val0):
154 return _InternalMux(self, val1, val0)
155
156 def __bool__(self):
157 raise TypeError("Attempted to convert nMigen value to Python boolean")
158
159 def __invert__(self):
160 return Operator("~", [self])
161 def __neg__(self):
162 return Operator("-", [self])
163
164 def __add__(self, other):
165 return Operator("+", [self, other])
166 def __radd__(self, other):
167 return Operator("+", [other, self])
168 def __sub__(self, other):
169 return Operator("-", [self, other])
170 def __rsub__(self, other):
171 return Operator("-", [other, self])
172
173 def __mul__(self, other):
174 return Operator("*", [self, other])
175 def __rmul__(self, other):
176 return Operator("*", [other, self])
177
178 def __check_divisor(self):
179 width, signed = self.shape()
180 if signed:
181 # Python's division semantics and Verilog's division semantics differ for negative
182 # divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
183 # completely by prohibiting such division operations.
184 raise NotImplementedError("Division by a signed value is not supported")
185 def __mod__(self, other):
186 other = Value.cast(other)
187 other.__check_divisor()
188 return Operator("%", [self, other])
189 def __rmod__(self, other):
190 self.__check_divisor()
191 return Operator("%", [other, self])
192 def __floordiv__(self, other):
193 other = Value.cast(other)
194 other.__check_divisor()
195 return Operator("//", [self, other])
196 def __rfloordiv__(self, other):
197 self.__check_divisor()
198 return Operator("//", [other, self])
199
200 def __check_shamt(self):
201 width, signed = self.shape()
202 if signed:
203 # Neither Python nor HDLs implement shifts by negative values; prohibit any shifts
204 # by a signed value to make sure the shift amount can always be interpreted as
205 # an unsigned value.
206 raise TypeError("Shift amount must be unsigned")
207 def __lshift__(self, other):
208 other = Value.cast(other)
209 other.__check_shamt()
210 return Operator("<<", [self, other])
211 def __rlshift__(self, other):
212 self.__check_shamt()
213 return Operator("<<", [other, self])
214 def __rshift__(self, other):
215 other = Value.cast(other)
216 other.__check_shamt()
217 return Operator(">>", [self, other])
218 def __rrshift__(self, other):
219 self.__check_shamt()
220 return Operator(">>", [other, self])
221
222 def __and__(self, other):
223 return Operator("&", [self, other])
224 def __rand__(self, other):
225 return Operator("&", [other, self])
226 def __xor__(self, other):
227 return Operator("^", [self, other])
228 def __rxor__(self, other):
229 return Operator("^", [other, self])
230 def __or__(self, other):
231 return Operator("|", [self, other])
232 def __ror__(self, other):
233 return Operator("|", [other, self])
234
235 def __eq__(self, other):
236 return Operator("==", [self, other])
237 def __ne__(self, other):
238 return Operator("!=", [self, other])
239 def __lt__(self, other):
240 return Operator("<", [self, other])
241 def __le__(self, other):
242 return Operator("<=", [self, other])
243 def __gt__(self, other):
244 return Operator(">", [self, other])
245 def __ge__(self, other):
246 return Operator(">=", [self, other])
247
248 def __abs__(self):
249 width, signed = self.shape()
250 if signed:
251 return Mux(self >= 0, self, -self)
252 else:
253 return self
254
255 def __len__(self):
256 return self.shape().width
257
258 def __getitem__(self, key):
259 n = len(self)
260 if isinstance(key, int):
261 if key not in range(-n, n):
262 raise IndexError(f"Index {key} is out of bounds for a {n}-bit value")
263 if key < 0:
264 key += n
265 return Slice(self, key, key + 1)
266 elif isinstance(key, slice):
267 start, stop, step = key.indices(n)
268 if step != 1:
269 return Cat(self[i] for i in range(start, stop, step))
270 return Slice(self, start, stop)
271 else:
272 raise TypeError("Cannot index value with {}".format(repr(key)))
273
274 def as_unsigned(self):
275 """Conversion to unsigned.
276
277 Returns
278 -------
279 Value, out
280 This ``Value`` reinterpreted as a unsigned integer.
281 """
282 return Operator("u", [self])
283
284 def as_signed(self):
285 """Conversion to signed.
286
287 Returns
288 -------
289 Value, out
290 This ``Value`` reinterpreted as a signed integer.
291 """
292 return Operator("s", [self])
293
294 def bool(self):
295 """Conversion to boolean.
296
297 Returns
298 -------
299 Value, out
300 ``1`` if any bits are set, ``0`` otherwise.
301 """
302 return Operator("b", [self])
303
304 def any(self):
305 """Check if any bits are ``1``.
306
307 Returns
308 -------
309 Value, out
310 ``1`` if any bits are set, ``0`` otherwise.
311 """
312 return Operator("r|", [self])
313
314 def all(self):
315 """Check if all bits are ``1``.
316
317 Returns
318 -------
319 Value, out
320 ``1`` if all bits are set, ``0`` otherwise.
321 """
322 return Operator("r&", [self])
323
324 def xor(self):
325 """Compute pairwise exclusive-or of every bit.
326
327 Returns
328 -------
329 Value, out
330 ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set.
331 """
332 return Operator("r^", [self])
333
334 def implies(premise, conclusion):
335 """Implication.
336
337 Returns
338 -------
339 Value, out
340 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
341 """
342 return ~premise | conclusion
343
344 def bit_select(self, offset, width):
345 """Part-select with bit granularity.
346
347 Selects a constant width but variable offset part of a ``Value``, such that successive
348 parts overlap by all but 1 bit.
349
350 Parameters
351 ----------
352 offset : Value, int
353 Index of first selected bit.
354 width : int
355 Number of selected bits.
356
357 Returns
358 -------
359 Part, out
360 Selected part of the ``Value``
361 """
362 offset = Value.cast(offset)
363 if type(offset) is Const and isinstance(width, int):
364 return self[offset.value:offset.value + width]
365 return Part(self, offset, width, stride=1, src_loc_at=1)
366
367 def word_select(self, offset, width):
368 """Part-select with word granularity.
369
370 Selects a constant width but variable offset part of a ``Value``, such that successive
371 parts do not overlap.
372
373 Parameters
374 ----------
375 offset : Value, int
376 Index of first selected word.
377 width : int
378 Number of selected bits.
379
380 Returns
381 -------
382 Part, out
383 Selected part of the ``Value``
384 """
385 offset = Value.cast(offset)
386 if type(offset) is Const and isinstance(width, int):
387 return self[offset.value * width:(offset.value + 1) * width]
388 return Part(self, offset, width, stride=width, src_loc_at=1)
389
390 def matches(self, *patterns):
391 """Pattern matching.
392
393 Matches against a set of patterns, which may be integers or bit strings, recognizing
394 the same grammar as ``Case()``.
395
396 Parameters
397 ----------
398 patterns : int or str
399 Patterns to match against.
400
401 Returns
402 -------
403 Value, out
404 ``1`` if any pattern matches the value, ``0`` otherwise.
405 """
406 matches = []
407 for pattern in patterns:
408 if not isinstance(pattern, (int, str, Enum)):
409 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
410 "not {!r}"
411 .format(pattern))
412 if isinstance(pattern, str) and any(bit not in "01- \t" for bit in pattern):
413 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
414 "bits, and may include whitespace"
415 .format(pattern))
416 if (isinstance(pattern, str) and
417 len("".join(pattern.split())) != len(self)):
418 raise SyntaxError("Match pattern '{}' must have the same width as match value "
419 "(which is {})"
420 .format(pattern, len(self)))
421 if isinstance(pattern, int) and bits_for(pattern) > len(self):
422 warnings.warn("Match pattern '{:b}' is wider than match value "
423 "(which has width {}); comparison will never be true"
424 .format(pattern, len(self)),
425 SyntaxWarning, stacklevel=3)
426 continue
427 if isinstance(pattern, str):
428 pattern = "".join(pattern.split()) # remove whitespace
429 mask = int(pattern.replace("0", "1").replace("-", "0"), 2)
430 pattern = int(pattern.replace("-", "0"), 2)
431 matches.append((self & mask) == pattern)
432 elif isinstance(pattern, int):
433 matches.append(self == pattern)
434 elif isinstance(pattern, Enum):
435 matches.append(self == pattern.value)
436 else:
437 assert False
438 if not matches:
439 return Const(0)
440 elif len(matches) == 1:
441 return matches[0]
442 else:
443 return Cat(*matches).any()
444
445 def shift_left(self, amount):
446 """Shift left by constant amount.
447
448 Parameters
449 ----------
450 amount : int
451 Amount to shift by.
452
453 Returns
454 -------
455 Value, out
456 If the amount is positive, the input shifted left. Otherwise, the input shifted right.
457 """
458 if not isinstance(amount, int):
459 raise TypeError("Shift amount must be an integer, not {!r}".format(amount))
460 if amount < 0:
461 return self.shift_right(-amount)
462 if self.shape().signed:
463 return Cat(Const(0, amount), self).as_signed()
464 else:
465 return Cat(Const(0, amount), self) # unsigned
466
467 def shift_right(self, amount):
468 """Shift right by constant amount.
469
470 Parameters
471 ----------
472 amount : int
473 Amount to shift by.
474
475 Returns
476 -------
477 Value, out
478 If the amount is positive, the input shifted right. Otherwise, the input shifted left.
479 """
480 if not isinstance(amount, int):
481 raise TypeError("Shift amount must be an integer, not {!r}".format(amount))
482 if amount < 0:
483 return self.shift_left(-amount)
484 if self.shape().signed:
485 return self[amount:].as_signed()
486 else:
487 return self[amount:] # unsigned
488
489 def rotate_left(self, amount):
490 """Rotate left by constant amount.
491
492 Parameters
493 ----------
494 amount : int
495 Amount to rotate by.
496
497 Returns
498 -------
499 Value, out
500 If the amount is positive, the input rotated left. Otherwise, the input rotated right.
501 """
502 if not isinstance(amount, int):
503 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount))
504 amount %= len(self)
505 return Cat(self[-amount:], self[:-amount]) # meow :3
506
507 def rotate_right(self, amount):
508 """Rotate right by constant amount.
509
510 Parameters
511 ----------
512 amount : int
513 Amount to rotate by.
514
515 Returns
516 -------
517 Value, out
518 If the amount is positive, the input rotated right. Otherwise, the input rotated right.
519 """
520 if not isinstance(amount, int):
521 raise TypeError("Rotate amount must be an integer, not {!r}".format(amount))
522 amount %= len(self)
523 return Cat(self[amount:], self[:amount])
524
525 def eq(self, value):
526 """Assignment.
527
528 Parameters
529 ----------
530 value : Value, in
531 Value to be assigned.
532
533 Returns
534 -------
535 Assign
536 Assignment statement that can be used in combinatorial or synchronous context.
537 """
538 return Assign(self, value, src_loc_at=1)
539
540 @abstractmethod
541 def shape(self):
542 """Bit width and signedness of a value.
543
544 Returns
545 -------
546 Shape
547 See :class:`Shape`.
548
549 Examples
550 --------
551 >>> Signal(8).shape()
552 Shape(width=8, signed=False)
553 >>> Const(0xaa).shape()
554 Shape(width=8, signed=False)
555 """
556 pass # :nocov:
557
558 def _lhs_signals(self):
559 raise TypeError("Value {!r} cannot be used in assignments".format(self))
560
561 @abstractmethod
562 def _rhs_signals(self):
563 pass # :nocov:
564
565 def _as_const(self):
566 raise TypeError("Value {!r} cannot be evaluated as constant".format(self))
567
568 __hash__ = None
569
570
571 @final
572 class Const(Value):
573 """A constant, literal integer value.
574
575 Parameters
576 ----------
577 value : int
578 shape : int or tuple or None
579 Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
580 in this constant and whether it is signed (can represent negative values).
581 ``shape`` defaults to the minimum possible width and signedness of ``value``.
582
583 Attributes
584 ----------
585 width : int
586 signed : bool
587 """
588 src_loc = None
589
590 @staticmethod
591 def normalize(value, shape):
592 width, signed = shape
593 mask = (1 << width) - 1
594 value &= mask
595 if signed and value >> (width - 1):
596 value |= ~mask
597 return value
598
599 def __init__(self, value, shape=None, *, src_loc_at=0):
600 # We deliberately do not call Value.__init__ here.
601 self.value = int(value)
602 if shape is None:
603 shape = Shape(bits_for(self.value), signed=self.value < 0)
604 elif isinstance(shape, int):
605 shape = Shape(shape, signed=self.value < 0)
606 else:
607 shape = Shape.cast(shape, src_loc_at=1 + src_loc_at)
608 self.width, self.signed = shape
609 self.value = self.normalize(self.value, shape)
610
611 def shape(self):
612 return Shape(self.width, self.signed)
613
614 def _rhs_signals(self):
615 return SignalSet()
616
617 def _as_const(self):
618 return self.value
619
620 def __repr__(self):
621 return "(const {}'{}d{})".format(self.width, "s" if self.signed else "", self.value)
622
623
624 C = Const # shorthand
625
626
627 class AnyValue(Value, DUID):
628 def __init__(self, shape, *, src_loc_at=0):
629 super().__init__(src_loc_at=src_loc_at)
630 self.width, self.signed = Shape.cast(shape, src_loc_at=1 + src_loc_at)
631 if not isinstance(self.width, int) or self.width < 0:
632 raise TypeError("Width must be a non-negative integer, not {!r}"
633 .format(self.width))
634
635 def shape(self):
636 return Shape(self.width, self.signed)
637
638 def _rhs_signals(self):
639 return SignalSet()
640
641
642 @final
643 class AnyConst(AnyValue):
644 def __repr__(self):
645 return "(anyconst {}'{})".format(self.width, "s" if self.signed else "")
646
647
648 @final
649 class AnySeq(AnyValue):
650 def __repr__(self):
651 return "(anyseq {}'{})".format(self.width, "s" if self.signed else "")
652
653
654 @final
655 class Operator(Value):
656 def __init__(self, operator, operands, *, src_loc_at=0):
657 super().__init__(src_loc_at=1 + src_loc_at)
658 self.operator = operator
659 self.operands = [Value.cast(op) for op in operands]
660
661 def shape(self):
662 def _bitwise_binary_shape(a_shape, b_shape):
663 a_bits, a_sign = a_shape
664 b_bits, b_sign = b_shape
665 if not a_sign and not b_sign:
666 # both operands unsigned
667 return Shape(max(a_bits, b_bits), False)
668 elif a_sign and b_sign:
669 # both operands signed
670 return Shape(max(a_bits, b_bits), True)
671 elif not a_sign and b_sign:
672 # first operand unsigned (add sign bit), second operand signed
673 return Shape(max(a_bits + 1, b_bits), True)
674 else:
675 # first signed, second operand unsigned (add sign bit)
676 return Shape(max(a_bits, b_bits + 1), True)
677
678 op_shapes = list(map(lambda x: x.shape(), self.operands))
679 if len(op_shapes) == 1:
680 (a_width, a_signed), = op_shapes
681 if self.operator in ("+", "~"):
682 return Shape(a_width, a_signed)
683 if self.operator == "-":
684 return Shape(a_width + 1, True)
685 if self.operator in ("b", "r|", "r&", "r^"):
686 return Shape(1, False)
687 if self.operator == "u":
688 return Shape(a_width, False)
689 if self.operator == "s":
690 return Shape(a_width, True)
691 elif len(op_shapes) == 2:
692 (a_width, a_signed), (b_width, b_signed) = op_shapes
693 if self.operator in ("+", "-"):
694 width, signed = _bitwise_binary_shape(*op_shapes)
695 return Shape(width + 1, signed)
696 if self.operator == "*":
697 return Shape(a_width + b_width, a_signed or b_signed)
698 if self.operator in ("//", "%"):
699 assert not b_signed
700 return Shape(a_width, a_signed)
701 if self.operator in ("<", "<=", "==", "!=", ">", ">="):
702 return Shape(1, False)
703 if self.operator in ("&", "^", "|"):
704 return _bitwise_binary_shape(*op_shapes)
705 if self.operator == "<<":
706 assert not b_signed
707 return Shape(a_width + 2 ** b_width - 1, a_signed)
708 if self.operator == ">>":
709 assert not b_signed
710 return Shape(a_width, a_signed)
711 elif len(op_shapes) == 3:
712 if self.operator == "m":
713 s_shape, a_shape, b_shape = op_shapes
714 return _bitwise_binary_shape(a_shape, b_shape)
715 raise NotImplementedError("Operator {}/{} not implemented"
716 .format(self.operator, len(op_shapes))) # :nocov:
717
718 def _rhs_signals(self):
719 return union(op._rhs_signals() for op in self.operands)
720
721 def __repr__(self):
722 return "({} {})".format(self.operator, " ".join(map(repr, self.operands)))
723
724
725 def Mux(sel, val1, val0):
726 sel = Value.cast(sel)
727 if len(sel) != 1:
728 sel = sel.bool()
729 return sel.__Mux__(val1, val0)
730
731
732 def _InternalMux(sel, val1, val0):
733 """Choose between two values.
734
735 Parameters
736 ----------
737 sel : Value, in
738 Selector.
739 val1 : Value, in
740 val0 : Value, in
741 Input values.
742
743 Returns
744 -------
745 Value, out
746 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
747 """
748 sel = Value.cast(sel)
749 if len(sel) != 1:
750 sel = sel.bool()
751 return Operator("m", [sel, val1, val0])
752
753
754 @final
755 class Slice(Value):
756 def __init__(self, value, start, stop, *, src_loc_at=0):
757 if not isinstance(start, int):
758 raise TypeError("Slice start must be an integer, not {!r}".format(start))
759 if not isinstance(stop, int):
760 raise TypeError("Slice stop must be an integer, not {!r}".format(stop))
761
762 n = len(value)
763 if start not in range(-(n+1), n+1):
764 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start, n))
765 if start < 0:
766 start += n
767 if stop not in range(-(n+1), n+1):
768 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop, n))
769 if stop < 0:
770 stop += n
771 if start > stop:
772 raise IndexError("Slice start {} must be less than slice stop {}".format(start, stop))
773
774 super().__init__(src_loc_at=src_loc_at)
775 self.value = Value.cast(value)
776 self.start = int(start)
777 self.stop = int(stop)
778
779 def shape(self):
780 return Shape(self.stop - self.start)
781
782 def _lhs_signals(self):
783 return self.value._lhs_signals()
784
785 def _rhs_signals(self):
786 return self.value._rhs_signals()
787
788 def __repr__(self):
789 return "(slice {} {}:{})".format(repr(self.value), self.start, self.stop)
790
791
792 @final
793 class Part(Value):
794 def __init__(self, value, offset, width, stride=1, *, src_loc_at=0):
795 if not isinstance(width, int) or width < 0:
796 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width))
797 if not isinstance(stride, int) or stride <= 0:
798 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride))
799
800 super().__init__(src_loc_at=src_loc_at)
801 self.value = value
802 self.offset = Value.cast(offset)
803 self.width = width
804 self.stride = stride
805
806 def shape(self):
807 return Shape(self.width)
808
809 def _lhs_signals(self):
810 return self.value._lhs_signals()
811
812 def _rhs_signals(self):
813 return self.value._rhs_signals() | self.offset._rhs_signals()
814
815 def __repr__(self):
816 return "(part {} {} {} {})".format(repr(self.value), repr(self.offset),
817 self.width, self.stride)
818
819
820 @final
821 class Cat(Value):
822 """Concatenate values.
823
824 Form a compound ``Value`` from several smaller ones by concatenation.
825 The first argument occupies the lower bits of the result.
826 The return value can be used on either side of an assignment, that
827 is, the concatenated value can be used as an argument on the RHS or
828 as a target on the LHS. If it is used on the LHS, it must solely
829 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
830 meeting these properties. The bit length of the return value is the sum of
831 the bit lengths of the arguments::
832
833 len(Cat(args)) == sum(len(arg) for arg in args)
834
835 Parameters
836 ----------
837 *args : Values or iterables of Values, inout
838 ``Value`` s to be concatenated.
839
840 Returns
841 -------
842 Value, inout
843 Resulting ``Value`` obtained by concatentation.
844 """
845 def __init__(self, *args, src_loc_at=0):
846 super().__init__(src_loc_at=src_loc_at)
847 self.parts = [Value.cast(v) for v in flatten(args)]
848
849 def shape(self):
850 return Shape(sum(len(part) for part in self.parts))
851
852 def _lhs_signals(self):
853 return union((part._lhs_signals() for part in self.parts), start=SignalSet())
854
855 def _rhs_signals(self):
856 return union((part._rhs_signals() for part in self.parts), start=SignalSet())
857
858 def _as_const(self):
859 value = 0
860 for part in reversed(self.parts):
861 value <<= len(part)
862 value |= part._as_const()
863 return value
864
865 def __repr__(self):
866 return "(cat {})".format(" ".join(map(repr, self.parts)))
867
868
869 @final
870 class Repl(Value):
871 """Replicate a value
872
873 An input value is replicated (repeated) several times
874 to be used on the RHS of assignments::
875
876 len(Repl(s, n)) == len(s) * n
877
878 Parameters
879 ----------
880 value : Value, in
881 Input value to be replicated.
882 count : int
883 Number of replications.
884
885 Returns
886 -------
887 Repl, out
888 Replicated value.
889 """
890 def __init__(self, value, count, *, src_loc_at=0):
891 if not isinstance(count, int) or count < 0:
892 raise TypeError("Replication count must be a non-negative integer, not {!r}"
893 .format(count))
894
895 super().__init__(src_loc_at=src_loc_at)
896 self.value = Value.cast(value)
897 self.count = count
898
899 def shape(self):
900 return Shape(len(self.value) * self.count)
901
902 def _rhs_signals(self):
903 return self.value._rhs_signals()
904
905 def __repr__(self):
906 return "(repl {!r} {})".format(self.value, self.count)
907
908
909 # @final
910 class Signal(Value, DUID):
911 """A varying integer value.
912
913 Parameters
914 ----------
915 shape : ``Shape``-castable object or None
916 Specification for the number of bits in this ``Signal`` and its signedness (whether it
917 can represent negative values). See ``Shape.cast`` for details.
918 If not specified, ``shape`` defaults to 1-bit and non-signed.
919 name : str
920 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
921 name this ``Signal`` is assigned to.
922 reset : int or integral Enum
923 Reset (synchronous) or default (combinatorial) value.
924 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
925 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
926 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
927 assumes its ``reset`` value. Defaults to 0.
928 reset_less : bool
929 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
930 The ``reset`` value is only used as a combinatorial default or as the initial value.
931 Defaults to ``False``.
932 attrs : dict
933 Dictionary of synthesis attributes.
934 decoder : function or Enum
935 A function converting integer signal values to human-readable strings (e.g. FSM state
936 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
937 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
938 the enumeration.
939
940 Attributes
941 ----------
942 width : int
943 signed : bool
944 name : str
945 reset : int
946 reset_less : bool
947 attrs : dict
948 decoder : function
949 """
950
951 def __init__(self, shape=None, *, name=None, reset=0, reset_less=False,
952 attrs=None, decoder=None, src_loc_at=0):
953 super().__init__(src_loc_at=src_loc_at)
954
955 if name is not None and not isinstance(name, str):
956 raise TypeError("Name must be a string, not {!r}".format(name))
957 self.name = name or tracer.get_var_name(depth=2 + src_loc_at, default="$signal")
958
959 if shape is None:
960 shape = unsigned(1)
961 self.width, self.signed = Shape.cast(shape, src_loc_at=1 + src_loc_at)
962
963 if isinstance(reset, Enum):
964 reset = reset.value
965 if not isinstance(reset, int):
966 raise TypeError("Reset value has to be an int or an integral Enum")
967
968 reset_width = bits_for(reset, self.signed)
969 if reset != 0 and reset_width > self.width:
970 warnings.warn("Reset value {!r} requires {} bits to represent, but the signal "
971 "only has {} bits"
972 .format(reset, reset_width, self.width),
973 SyntaxWarning, stacklevel=2 + src_loc_at)
974
975 self.reset = reset
976 self.reset_less = bool(reset_less)
977
978 self.attrs = OrderedDict(() if attrs is None else attrs)
979
980 if decoder is None and isinstance(shape, type) and issubclass(shape, Enum):
981 decoder = shape
982 if isinstance(decoder, type) and issubclass(decoder, Enum):
983 def enum_decoder(value):
984 try:
985 return "{0.name:}/{0.value:}".format(decoder(value))
986 except ValueError:
987 return str(value)
988 self.decoder = enum_decoder
989 self._enum_class = decoder
990 else:
991 self.decoder = decoder
992 self._enum_class = None
993
994 # Not a @classmethod because nmigen.compat requires it.
995 @staticmethod
996 def like(other, *, name=None, name_suffix=None, src_loc_at=0, **kwargs):
997 """Create Signal based on another.
998
999 Parameters
1000 ----------
1001 other : Value
1002 Object to base this Signal on.
1003 """
1004 if name is not None:
1005 new_name = str(name)
1006 elif name_suffix is not None:
1007 new_name = other.name + str(name_suffix)
1008 else:
1009 new_name = tracer.get_var_name(depth=2 + src_loc_at, default="$like")
1010 kw = dict(shape=Value.cast(other).shape(), name=new_name)
1011 if isinstance(other, Signal):
1012 kw.update(reset=other.reset, reset_less=other.reset_less,
1013 attrs=other.attrs, decoder=other.decoder)
1014 kw.update(kwargs)
1015 return Signal(**kw, src_loc_at=1 + src_loc_at)
1016
1017 def shape(self):
1018 return Shape(self.width, self.signed)
1019
1020 def _lhs_signals(self):
1021 return SignalSet((self,))
1022
1023 def _rhs_signals(self):
1024 return SignalSet((self,))
1025
1026 def __repr__(self):
1027 return "(sig {})".format(self.name)
1028
1029
1030 @final
1031 class ClockSignal(Value):
1032 """Clock signal for a clock domain.
1033
1034 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
1035 All of these signals ultimately refer to the same signal, but they can be manipulated
1036 independently of the clock domain, even before the clock domain is created.
1037
1038 Parameters
1039 ----------
1040 domain : str
1041 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
1042 """
1043 def __init__(self, domain="sync", *, src_loc_at=0):
1044 super().__init__(src_loc_at=src_loc_at)
1045 if not isinstance(domain, str):
1046 raise TypeError("Clock domain name must be a string, not {!r}".format(domain))
1047 if domain == "comb":
1048 raise ValueError("Domain '{}' does not have a clock".format(domain))
1049 self.domain = domain
1050
1051 def shape(self):
1052 return Shape(1)
1053
1054 def _lhs_signals(self):
1055 return SignalSet((self,))
1056
1057 def _rhs_signals(self):
1058 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
1059
1060 def __repr__(self):
1061 return "(clk {})".format(self.domain)
1062
1063
1064 @final
1065 class ResetSignal(Value):
1066 """Reset signal for a clock domain.
1067
1068 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
1069 All of these signals ultimately refer to the same signal, but they can be manipulated
1070 independently of the clock domain, even before the clock domain is created.
1071
1072 Parameters
1073 ----------
1074 domain : str
1075 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
1076 allow_reset_less : bool
1077 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
1078 """
1079 def __init__(self, domain="sync", allow_reset_less=False, *, src_loc_at=0):
1080 super().__init__(src_loc_at=src_loc_at)
1081 if not isinstance(domain, str):
1082 raise TypeError("Clock domain name must be a string, not {!r}".format(domain))
1083 if domain == "comb":
1084 raise ValueError("Domain '{}' does not have a reset".format(domain))
1085 self.domain = domain
1086 self.allow_reset_less = allow_reset_less
1087
1088 def shape(self):
1089 return Shape(1)
1090
1091 def _lhs_signals(self):
1092 return SignalSet((self,))
1093
1094 def _rhs_signals(self):
1095 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
1096
1097 def __repr__(self):
1098 return "(rst {})".format(self.domain)
1099
1100
1101 class Array(MutableSequence):
1102 """Addressable multiplexer.
1103
1104 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
1105 in a proxy.
1106
1107 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
1108 assignments, provided that all elements of the array are values. The array proxy also supports
1109 attribute access and further indexing, each returning another array proxy; this means that
1110 the results of indexing into arrays, arrays of records, and arrays of arrays can all
1111 be used as first-class values.
1112
1113 It is an error to change an array or any of its elements after an array proxy was created.
1114 Changing the array directly will raise an exception. However, it is not possible to detect
1115 the elements being modified; if an element's attribute or element is modified after the proxy
1116 for it has been created, the proxy will refer to stale data.
1117
1118 Examples
1119 --------
1120
1121 Simple array::
1122
1123 gpios = Array(Signal() for _ in range(10))
1124 with m.If(bus.we):
1125 m.d.sync += gpios[bus.addr].eq(bus.w_data)
1126 with m.Else():
1127 m.d.sync += bus.r_data.eq(gpios[bus.addr])
1128
1129 Multidimensional array::
1130
1131 mult = Array(Array(x * y for y in range(10)) for x in range(10))
1132 a = Signal.range(10)
1133 b = Signal.range(10)
1134 r = Signal(8)
1135 m.d.comb += r.eq(mult[a][b])
1136
1137 Array of records::
1138
1139 layout = [
1140 ("r_data", 16),
1141 ("r_en", 1),
1142 ]
1143 buses = Array(Record(layout) for busno in range(4))
1144 master = Record(layout)
1145 m.d.comb += [
1146 buses[sel].r_en.eq(master.r_en),
1147 master.r_data.eq(buses[sel].r_data),
1148 ]
1149 """
1150 def __init__(self, iterable=()):
1151 self._inner = list(iterable)
1152 self._proxy_at = None
1153 self._mutable = True
1154
1155 def __getitem__(self, index):
1156 if isinstance(index, Value):
1157 if self._mutable:
1158 self._proxy_at = tracer.get_src_loc()
1159 self._mutable = False
1160 return ArrayProxy(self, index)
1161 else:
1162 return self._inner[index]
1163
1164 def __len__(self):
1165 return len(self._inner)
1166
1167 def _check_mutability(self):
1168 if not self._mutable:
1169 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1170 "at {}:{}".format(*self._proxy_at))
1171
1172 def __setitem__(self, index, value):
1173 self._check_mutability()
1174 self._inner[index] = value
1175
1176 def __delitem__(self, index):
1177 self._check_mutability()
1178 del self._inner[index]
1179
1180 def insert(self, index, value):
1181 self._check_mutability()
1182 self._inner.insert(index, value)
1183
1184 def __repr__(self):
1185 return "(array{} [{}])".format(" mutable" if self._mutable else "",
1186 ", ".join(map(repr, self._inner)))
1187
1188
1189 @final
1190 class ArrayProxy(Value):
1191 def __init__(self, elems, index, *, src_loc_at=0):
1192 super().__init__(src_loc_at=1 + src_loc_at)
1193 self.elems = elems
1194 self.index = Value.cast(index)
1195
1196 def __getattr__(self, attr):
1197 return ArrayProxy([getattr(elem, attr) for elem in self.elems], self.index)
1198
1199 def __getitem__(self, index):
1200 return ArrayProxy([ elem[index] for elem in self.elems], self.index)
1201
1202 def _iter_as_values(self):
1203 return (Value.cast(elem) for elem in self.elems)
1204
1205 def shape(self):
1206 unsigned_width = signed_width = 0
1207 has_unsigned = has_signed = False
1208 for elem_width, elem_signed in (elem.shape() for elem in self._iter_as_values()):
1209 if elem_signed:
1210 has_signed = True
1211 signed_width = max(signed_width, elem_width)
1212 else:
1213 has_unsigned = True
1214 unsigned_width = max(unsigned_width, elem_width)
1215 # The shape of the proxy must be such that it preserves the mathematical value of the array
1216 # elements. I.e., shape-wise, an array proxy must be identical to an equivalent mux tree.
1217 # To ensure this holds, if the array contains both signed and unsigned values, make sure
1218 # that every unsigned value is zero-extended by at least one bit.
1219 if has_signed and has_unsigned and unsigned_width >= signed_width:
1220 # Array contains both signed and unsigned values, and at least one of the unsigned
1221 # values won't be zero-extended otherwise.
1222 return signed(unsigned_width + 1)
1223 else:
1224 # Array contains values of the same signedness, or else all of the unsigned values
1225 # are zero-extended.
1226 return Shape(max(unsigned_width, signed_width), has_signed)
1227
1228 def _lhs_signals(self):
1229 signals = union((elem._lhs_signals() for elem in self._iter_as_values()),
1230 start=SignalSet())
1231 return signals
1232
1233 def _rhs_signals(self):
1234 signals = union((elem._rhs_signals() for elem in self._iter_as_values()),
1235 start=SignalSet())
1236 return self.index._rhs_signals() | signals
1237
1238 def __repr__(self):
1239 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self.elems)), self.index)
1240
1241
1242 # TODO(nmigen-0.4): remove
1243 class UserValue(Value):
1244 """Value with custom lowering.
1245
1246 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1247 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1248 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1249 value when required.
1250
1251 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1252 nMigen's view of representation of all values stays internally consistent. If the class
1253 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1254 it is not mutated in a way that changes its representation.
1255
1256 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1257 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1258 * Querying the shape using ``.shape()`` or ``len()``;
1259 * Creating a similarly shaped signal using ``Signal.like``;
1260 * Indexing or iterating through individual bits;
1261 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1262 """
1263 @deprecated("instead of `UserValue`, use `ValueCastable`", stacklevel=3)
1264 def __init__(self, *, src_loc_at=0):
1265 super().__init__(src_loc_at=1 + src_loc_at)
1266 self.__lowered = None
1267
1268 @abstractmethod
1269 def lower(self):
1270 """Conversion to a concrete representation."""
1271 pass # :nocov:
1272
1273 def _lazy_lower(self):
1274 if self.__lowered is None:
1275 lowered = self.lower()
1276 if isinstance(lowered, UserValue):
1277 lowered = lowered._lazy_lower()
1278 self.__lowered = Value.cast(lowered)
1279 return self.__lowered
1280
1281 def shape(self):
1282 return self._lazy_lower().shape()
1283
1284 def _lhs_signals(self):
1285 return self._lazy_lower()._lhs_signals()
1286
1287 def _rhs_signals(self):
1288 return self._lazy_lower()._rhs_signals()
1289
1290
1291 class ValueCastable:
1292 """Base class for classes which can be cast to Values.
1293
1294 A ``ValueCastable`` can be cast to ``Value``, meaning its precise representation does not have
1295 to be immediately known. This is useful in certain metaprogramming scenarios. Instead of
1296 providing fixed semantics upfront, it is kept abstract for as long as possible, only being
1297 cast to a concrete nMigen value when required.
1298
1299 Note that it is necessary to ensure that nMigen's view of representation of all values stays
1300 internally consistent. The class deriving from ``ValueCastable`` must decorate the ``as_value``
1301 method with the ``lowermethod`` decorator, which ensures that all calls to ``as_value`` return
1302 the same ``Value`` representation. If the class deriving from ``ValueCastable`` is mutable,
1303 it is up to the user to ensure that it is not mutated in a way that changes its representation
1304 after the first call to ``as_value``.
1305 """
1306 def __new__(cls, *args, **kwargs):
1307 self = super().__new__(cls)
1308 if not hasattr(self, "as_value"):
1309 raise TypeError(f"Class '{cls.__name__}' deriving from `ValueCastable` must override "
1310 "the `as_value` method")
1311
1312 if not hasattr(self.as_value, "_ValueCastable__memoized"):
1313 raise TypeError(f"Class '{cls.__name__}' deriving from `ValueCastable` must decorate "
1314 "the `as_value` method with the `ValueCastable.lowermethod` decorator")
1315 return self
1316
1317 @staticmethod
1318 def lowermethod(func):
1319 """Decorator to memoize lowering methods.
1320
1321 Ensures the decorated method is called only once, with subsequent method calls returning the
1322 object returned by the first first method call.
1323
1324 This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` subclasses.
1325 This is to ensure that nMigen's view of representation of all values stays internally
1326 consistent.
1327 """
1328 @functools.wraps(func)
1329 def wrapper_memoized(self, *args, **kwargs):
1330 if not hasattr(self, "_ValueCastable__lowered_to"):
1331 self.__lowered_to = func(self, *args, **kwargs)
1332 return self.__lowered_to
1333 wrapper_memoized.__memoized = True
1334 return wrapper_memoized
1335
1336
1337 @final
1338 class Sample(Value):
1339 """Value from the past.
1340
1341 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1342 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1343 to the value of the expression calculated as if each signal had its reset value.
1344 """
1345 def __init__(self, expr, clocks, domain, *, src_loc_at=0):
1346 super().__init__(src_loc_at=1 + src_loc_at)
1347 self.value = Value.cast(expr)
1348 self.clocks = int(clocks)
1349 self.domain = domain
1350 if not isinstance(self.value, (Const, Signal, ClockSignal, ResetSignal, Initial)):
1351 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1352 .format(self.value))
1353 if self.clocks < 0:
1354 raise ValueError("Cannot sample a value {} cycles in the future"
1355 .format(-self.clocks))
1356 if not (self.domain is None or isinstance(self.domain, str)):
1357 raise TypeError("Domain name must be a string or None, not {!r}"
1358 .format(self.domain))
1359
1360 def shape(self):
1361 return self.value.shape()
1362
1363 def _rhs_signals(self):
1364 return SignalSet((self,))
1365
1366 def __repr__(self):
1367 return "(sample {!r} @ {}[{}])".format(
1368 self.value, "<default>" if self.domain is None else self.domain, self.clocks)
1369
1370
1371 def Past(expr, clocks=1, domain=None):
1372 return Sample(expr, clocks, domain)
1373
1374
1375 def Stable(expr, clocks=0, domain=None):
1376 return Sample(expr, clocks + 1, domain) == Sample(expr, clocks, domain)
1377
1378
1379 def Rose(expr, clocks=0, domain=None):
1380 return ~Sample(expr, clocks + 1, domain) & Sample(expr, clocks, domain)
1381
1382
1383 def Fell(expr, clocks=0, domain=None):
1384 return Sample(expr, clocks + 1, domain) & ~Sample(expr, clocks, domain)
1385
1386
1387 @final
1388 class Initial(Value):
1389 """Start indicator, for model checking.
1390
1391 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1392 """
1393 def __init__(self, *, src_loc_at=0):
1394 super().__init__(src_loc_at=src_loc_at)
1395
1396 def shape(self):
1397 return Shape(1)
1398
1399 def _rhs_signals(self):
1400 return SignalSet((self,))
1401
1402 def __repr__(self):
1403 return "(initial)"
1404
1405
1406 class _StatementList(list):
1407 def __repr__(self):
1408 return "({})".format(" ".join(map(repr, self)))
1409
1410
1411 class Statement:
1412 def __init__(self, *, src_loc_at=0):
1413 self.src_loc = tracer.get_src_loc(1 + src_loc_at)
1414
1415 @staticmethod
1416 def cast(obj):
1417 if isinstance(obj, Iterable):
1418 return _StatementList(list(chain.from_iterable(map(Statement.cast, obj))))
1419 else:
1420 if isinstance(obj, Statement):
1421 return _StatementList([obj])
1422 else:
1423 raise TypeError("Object {!r} is not an nMigen statement".format(obj))
1424
1425
1426 @final
1427 class Assign(Statement):
1428 def __init__(self, lhs, rhs, *, src_loc_at=0):
1429 super().__init__(src_loc_at=src_loc_at)
1430 self.lhs = Value.cast(lhs)
1431 self.rhs = Value.cast(rhs)
1432
1433 def _lhs_signals(self):
1434 return self.lhs._lhs_signals()
1435
1436 def _rhs_signals(self):
1437 return self.lhs._rhs_signals() | self.rhs._rhs_signals()
1438
1439 def __repr__(self):
1440 return "(eq {!r} {!r})".format(self.lhs, self.rhs)
1441
1442
1443 class UnusedProperty(UnusedMustUse):
1444 pass
1445
1446
1447 class Property(Statement, MustUse):
1448 _MustUse__warning = UnusedProperty
1449
1450 def __init__(self, test, *, _check=None, _en=None, src_loc_at=0):
1451 super().__init__(src_loc_at=src_loc_at)
1452 self.test = Value.cast(test)
1453 self._check = _check
1454 self._en = _en
1455 if self._check is None:
1456 self._check = Signal(reset_less=True, name="${}$check".format(self._kind))
1457 self._check.src_loc = self.src_loc
1458 if _en is None:
1459 self._en = Signal(reset_less=True, name="${}$en".format(self._kind))
1460 self._en.src_loc = self.src_loc
1461
1462 def _lhs_signals(self):
1463 return SignalSet((self._en, self._check))
1464
1465 def _rhs_signals(self):
1466 return self.test._rhs_signals()
1467
1468 def __repr__(self):
1469 return "({} {!r})".format(self._kind, self.test)
1470
1471
1472 @final
1473 class Assert(Property):
1474 _kind = "assert"
1475
1476
1477 @final
1478 class Assume(Property):
1479 _kind = "assume"
1480
1481
1482 @final
1483 class Cover(Property):
1484 _kind = "cover"
1485
1486
1487 # @final
1488 class Switch(Statement):
1489 def __init__(self, test, cases, *, src_loc=None, src_loc_at=0, case_src_locs={}):
1490 if src_loc is None:
1491 super().__init__(src_loc_at=src_loc_at)
1492 else:
1493 # Switch is a bit special in terms of location tracking because it is usually created
1494 # long after the control has left the statement that directly caused its creation.
1495 self.src_loc = src_loc
1496 # Switch is also a bit special in that its parts also have location information. It can't
1497 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1498 self.case_src_locs = {}
1499
1500 self.test = Value.cast(test)
1501 self.cases = OrderedDict()
1502 for orig_keys, stmts in cases.items():
1503 # Map: None -> (); key -> (key,); (key...) -> (key...)
1504 keys = orig_keys
1505 if keys is None:
1506 keys = ()
1507 if not isinstance(keys, tuple):
1508 keys = (keys,)
1509 # Map: 2 -> "0010"; "0010" -> "0010"
1510 new_keys = ()
1511 key_mask = (1 << len(self.test)) - 1
1512 for key in keys:
1513 if isinstance(key, str):
1514 key = "".join(key.split()) # remove whitespace
1515 elif isinstance(key, int):
1516 key = format(key & key_mask, "b").rjust(len(self.test), "0")
1517 elif isinstance(key, Enum):
1518 key = format(key.value & key_mask, "b").rjust(len(self.test), "0")
1519 else:
1520 raise TypeError("Object {!r} cannot be used as a switch key"
1521 .format(key))
1522 assert len(key) == len(self.test)
1523 new_keys = (*new_keys, key)
1524 if not isinstance(stmts, Iterable):
1525 stmts = [stmts]
1526 self.cases[new_keys] = Statement.cast(stmts)
1527 if orig_keys in case_src_locs:
1528 self.case_src_locs[new_keys] = case_src_locs[orig_keys]
1529
1530 def _lhs_signals(self):
1531 signals = union((s._lhs_signals() for ss in self.cases.values() for s in ss),
1532 start=SignalSet())
1533 return signals
1534
1535 def _rhs_signals(self):
1536 signals = union((s._rhs_signals() for ss in self.cases.values() for s in ss),
1537 start=SignalSet())
1538 return self.test._rhs_signals() | signals
1539
1540 def __repr__(self):
1541 def case_repr(keys, stmts):
1542 stmts_repr = " ".join(map(repr, stmts))
1543 if keys == ():
1544 return "(default {})".format(stmts_repr)
1545 elif len(keys) == 1:
1546 return "(case {} {})".format(keys[0], stmts_repr)
1547 else:
1548 return "(case ({}) {})".format(" ".join(keys), stmts_repr)
1549 case_reprs = [case_repr(keys, stmts) for keys, stmts in self.cases.items()]
1550 return "(switch {!r} {})".format(self.test, " ".join(case_reprs))
1551
1552
1553 class _MappedKeyCollection(metaclass=ABCMeta):
1554 @abstractmethod
1555 def _map_key(self, key):
1556 pass # :nocov:
1557
1558 @abstractmethod
1559 def _unmap_key(self, key):
1560 pass # :nocov:
1561
1562
1563 class _MappedKeyDict(MutableMapping, _MappedKeyCollection):
1564 def __init__(self, pairs=()):
1565 self._storage = OrderedDict()
1566 for key, value in pairs:
1567 self[key] = value
1568
1569 def __getitem__(self, key):
1570 key = None if key is None else self._map_key(key)
1571 return self._storage[key]
1572
1573 def __setitem__(self, key, value):
1574 key = None if key is None else self._map_key(key)
1575 self._storage[key] = value
1576
1577 def __delitem__(self, key):
1578 key = None if key is None else self._map_key(key)
1579 del self._storage[key]
1580
1581 def __iter__(self):
1582 for key in self._storage:
1583 if key is None:
1584 yield None
1585 else:
1586 yield self._unmap_key(key)
1587
1588 def __eq__(self, other):
1589 if not isinstance(other, type(self)):
1590 return False
1591 if len(self) != len(other):
1592 return False
1593 for ak, bk in zip(sorted(self._storage), sorted(other._storage)):
1594 if ak != bk:
1595 return False
1596 if self._storage[ak] != other._storage[bk]:
1597 return False
1598 return True
1599
1600 def __len__(self):
1601 return len(self._storage)
1602
1603 def __repr__(self):
1604 pairs = ["({!r}, {!r})".format(k, v) for k, v in self.items()]
1605 return "{}.{}([{}])".format(type(self).__module__, type(self).__name__,
1606 ", ".join(pairs))
1607
1608
1609 class _MappedKeySet(MutableSet, _MappedKeyCollection):
1610 def __init__(self, elements=()):
1611 self._storage = OrderedDict()
1612 for elem in elements:
1613 self.add(elem)
1614
1615 def add(self, value):
1616 self._storage[self._map_key(value)] = None
1617
1618 def update(self, values):
1619 for value in values:
1620 self.add(value)
1621
1622 def discard(self, value):
1623 if value in self:
1624 del self._storage[self._map_key(value)]
1625
1626 def __contains__(self, value):
1627 return self._map_key(value) in self._storage
1628
1629 def __iter__(self):
1630 for key in [k for k in self._storage]:
1631 yield self._unmap_key(key)
1632
1633 def __len__(self):
1634 return len(self._storage)
1635
1636 def __repr__(self):
1637 return "{}.{}({})".format(type(self).__module__, type(self).__name__,
1638 ", ".join(repr(x) for x in self))
1639
1640
1641 class ValueKey:
1642 def __init__(self, value):
1643 self.value = Value.cast(value)
1644 if isinstance(self.value, Const):
1645 self._hash = hash(self.value.value)
1646 elif isinstance(self.value, (Signal, AnyValue)):
1647 self._hash = hash(self.value.duid)
1648 elif isinstance(self.value, (ClockSignal, ResetSignal)):
1649 self._hash = hash(self.value.domain)
1650 elif isinstance(self.value, Operator):
1651 self._hash = hash((self.value.operator,
1652 tuple(ValueKey(o) for o in self.value.operands)))
1653 elif isinstance(self.value, Slice):
1654 self._hash = hash((ValueKey(self.value.value), self.value.start, self.value.stop))
1655 elif isinstance(self.value, Part):
1656 self._hash = hash((ValueKey(self.value.value), ValueKey(self.value.offset),
1657 self.value.width, self.value.stride))
1658 elif isinstance(self.value, Cat):
1659 self._hash = hash(tuple(ValueKey(o) for o in self.value.parts))
1660 elif isinstance(self.value, ArrayProxy):
1661 self._hash = hash((ValueKey(self.value.index),
1662 tuple(ValueKey(e) for e in self.value._iter_as_values())))
1663 elif isinstance(self.value, Sample):
1664 self._hash = hash((ValueKey(self.value.value), self.value.clocks, self.value.domain))
1665 elif isinstance(self.value, Initial):
1666 self._hash = 0
1667 else: # :nocov:
1668 raise TypeError("Object {!r} cannot be used as a key in value collections"
1669 .format(self.value))
1670
1671 def __hash__(self):
1672 return self._hash
1673
1674 def __eq__(self, other):
1675 if type(other) is not ValueKey:
1676 return False
1677 if type(self.value) is not type(other.value):
1678 return False
1679
1680 if isinstance(self.value, Const):
1681 return self.value.value == other.value.value
1682 elif isinstance(self.value, (Signal, AnyValue)):
1683 return self.value is other.value
1684 elif isinstance(self.value, (ClockSignal, ResetSignal)):
1685 return self.value.domain == other.value.domain
1686 elif isinstance(self.value, Operator):
1687 return (self.value.operator == other.value.operator and
1688 len(self.value.operands) == len(other.value.operands) and
1689 all(ValueKey(a) == ValueKey(b)
1690 for a, b in zip(self.value.operands, other.value.operands)))
1691 elif isinstance(self.value, Slice):
1692 return (ValueKey(self.value.value) == ValueKey(other.value.value) and
1693 self.value.start == other.value.start and
1694 self.value.stop == other.value.stop)
1695 elif isinstance(self.value, Part):
1696 return (ValueKey(self.value.value) == ValueKey(other.value.value) and
1697 ValueKey(self.value.offset) == ValueKey(other.value.offset) and
1698 self.value.width == other.value.width and
1699 self.value.stride == other.value.stride)
1700 elif isinstance(self.value, Cat):
1701 return all(ValueKey(a) == ValueKey(b)
1702 for a, b in zip(self.value.parts, other.value.parts))
1703 elif isinstance(self.value, ArrayProxy):
1704 return (ValueKey(self.value.index) == ValueKey(other.value.index) and
1705 len(self.value.elems) == len(other.value.elems) and
1706 all(ValueKey(a) == ValueKey(b)
1707 for a, b in zip(self.value._iter_as_values(),
1708 other.value._iter_as_values())))
1709 elif isinstance(self.value, Sample):
1710 return (ValueKey(self.value.value) == ValueKey(other.value.value) and
1711 self.value.clocks == other.value.clocks and
1712 self.value.domain == self.value.domain)
1713 elif isinstance(self.value, Initial):
1714 return True
1715 else: # :nocov:
1716 raise TypeError("Object {!r} cannot be used as a key in value collections"
1717 .format(self.value))
1718
1719 def __lt__(self, other):
1720 if not isinstance(other, ValueKey):
1721 return False
1722 if type(self.value) != type(other.value):
1723 return False
1724
1725 if isinstance(self.value, Const):
1726 return self.value < other.value
1727 elif isinstance(self.value, (Signal, AnyValue)):
1728 return self.value.duid < other.value.duid
1729 elif isinstance(self.value, Slice):
1730 return (ValueKey(self.value.value) < ValueKey(other.value.value) and
1731 self.value.start < other.value.start and
1732 self.value.end < other.value.end)
1733 else: # :nocov:
1734 raise TypeError("Object {!r} cannot be used as a key in value collections")
1735
1736 def __repr__(self):
1737 return "<{}.ValueKey {!r}>".format(__name__, self.value)
1738
1739
1740 class ValueDict(_MappedKeyDict):
1741 _map_key = ValueKey
1742 _unmap_key = lambda self, key: key.value
1743
1744
1745 class ValueSet(_MappedKeySet):
1746 _map_key = ValueKey
1747 _unmap_key = lambda self, key: key.value
1748
1749
1750 class SignalKey:
1751 def __init__(self, signal):
1752 self.signal = signal
1753 if isinstance(signal, Signal):
1754 self._intern = (0, signal.duid)
1755 elif type(signal) is ClockSignal:
1756 self._intern = (1, signal.domain)
1757 elif type(signal) is ResetSignal:
1758 self._intern = (2, signal.domain)
1759 else:
1760 raise TypeError("Object {!r} is not an nMigen signal".format(signal))
1761
1762 def __hash__(self):
1763 return hash(self._intern)
1764
1765 def __eq__(self, other):
1766 if type(other) is not SignalKey:
1767 return False
1768 return self._intern == other._intern
1769
1770 def __lt__(self, other):
1771 if type(other) is not SignalKey:
1772 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal))
1773 return self._intern < other._intern
1774
1775 def __repr__(self):
1776 return "<{}.SignalKey {!r}>".format(__name__, self.signal)
1777
1778
1779 class SignalDict(_MappedKeyDict):
1780 _map_key = SignalKey
1781 _unmap_key = lambda self, key: key.signal
1782
1783
1784 class SignalSet(_MappedKeySet):
1785 _map_key = SignalKey
1786 _unmap_key = lambda self, key: key.signal