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