hdl.ast: don't inherit Shape from NamedTuple.
[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 width, signed = 0, False
1201 for elem_width, elem_signed in (elem.shape() for elem in self._iter_as_values()):
1202 width = max(width, elem_width + elem_signed)
1203 signed = max(signed, elem_signed)
1204 return Shape(width, signed)
1205
1206 def _lhs_signals(self):
1207 signals = union((elem._lhs_signals() for elem in self._iter_as_values()),
1208 start=SignalSet())
1209 return signals
1210
1211 def _rhs_signals(self):
1212 signals = union((elem._rhs_signals() for elem in self._iter_as_values()),
1213 start=SignalSet())
1214 return self.index._rhs_signals() | signals
1215
1216 def __repr__(self):
1217 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self.elems)), self.index)
1218
1219
1220 class UserValue(Value):
1221 """Value with custom lowering.
1222
1223 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1224 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1225 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1226 value when required.
1227
1228 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1229 nMigen's view of representation of all values stays internally consistent. If the class
1230 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1231 it is not mutated in a way that changes its representation.
1232
1233 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1234 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1235 * Querying the shape using ``.shape()`` or ``len()``;
1236 * Creating a similarly shaped signal using ``Signal.like``;
1237 * Indexing or iterating through individual bits;
1238 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1239 """
1240 def __init__(self, *, src_loc_at=0):
1241 super().__init__(src_loc_at=1 + src_loc_at)
1242 self.__lowered = None
1243
1244 @abstractmethod
1245 def lower(self):
1246 """Conversion to a concrete representation."""
1247 pass # :nocov:
1248
1249 def _lazy_lower(self):
1250 if self.__lowered is None:
1251 lowered = self.lower()
1252 if isinstance(lowered, UserValue):
1253 lowered = lowered._lazy_lower()
1254 self.__lowered = Value.cast(lowered)
1255 return self.__lowered
1256
1257 def shape(self):
1258 return self._lazy_lower().shape()
1259
1260 def _lhs_signals(self):
1261 return self._lazy_lower()._lhs_signals()
1262
1263 def _rhs_signals(self):
1264 return self._lazy_lower()._rhs_signals()
1265
1266
1267 @final
1268 class Sample(Value):
1269 """Value from the past.
1270
1271 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1272 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1273 to the value of the expression calculated as if each signal had its reset value.
1274 """
1275 def __init__(self, expr, clocks, domain, *, src_loc_at=0):
1276 super().__init__(src_loc_at=1 + src_loc_at)
1277 self.value = Value.cast(expr)
1278 self.clocks = int(clocks)
1279 self.domain = domain
1280 if not isinstance(self.value, (Const, Signal, ClockSignal, ResetSignal, Initial)):
1281 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1282 .format(self.value))
1283 if self.clocks < 0:
1284 raise ValueError("Cannot sample a value {} cycles in the future"
1285 .format(-self.clocks))
1286 if not (self.domain is None or isinstance(self.domain, str)):
1287 raise TypeError("Domain name must be a string or None, not {!r}"
1288 .format(self.domain))
1289
1290 def shape(self):
1291 return self.value.shape()
1292
1293 def _rhs_signals(self):
1294 return SignalSet((self,))
1295
1296 def __repr__(self):
1297 return "(sample {!r} @ {}[{}])".format(
1298 self.value, "<default>" if self.domain is None else self.domain, self.clocks)
1299
1300
1301 def Past(expr, clocks=1, domain=None):
1302 return Sample(expr, clocks, domain)
1303
1304
1305 def Stable(expr, clocks=0, domain=None):
1306 return Sample(expr, clocks + 1, domain) == Sample(expr, clocks, domain)
1307
1308
1309 def Rose(expr, clocks=0, domain=None):
1310 return ~Sample(expr, clocks + 1, domain) & Sample(expr, clocks, domain)
1311
1312
1313 def Fell(expr, clocks=0, domain=None):
1314 return Sample(expr, clocks + 1, domain) & ~Sample(expr, clocks, domain)
1315
1316
1317 @final
1318 class Initial(Value):
1319 """Start indicator, for model checking.
1320
1321 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1322 """
1323 def __init__(self, *, src_loc_at=0):
1324 super().__init__(src_loc_at=src_loc_at)
1325
1326 def shape(self):
1327 return Shape(1)
1328
1329 def _rhs_signals(self):
1330 return SignalSet((self,))
1331
1332 def __repr__(self):
1333 return "(initial)"
1334
1335
1336 class _StatementList(list):
1337 def __repr__(self):
1338 return "({})".format(" ".join(map(repr, self)))
1339
1340
1341 class Statement:
1342 def __init__(self, *, src_loc_at=0):
1343 self.src_loc = tracer.get_src_loc(1 + src_loc_at)
1344
1345 @staticmethod
1346 def cast(obj):
1347 if isinstance(obj, Iterable):
1348 return _StatementList(sum((Statement.cast(e) for e in obj), []))
1349 else:
1350 if isinstance(obj, Statement):
1351 return _StatementList([obj])
1352 else:
1353 raise TypeError("Object {!r} is not an nMigen statement".format(obj))
1354
1355
1356 @final
1357 class Assign(Statement):
1358 def __init__(self, lhs, rhs, *, src_loc_at=0):
1359 super().__init__(src_loc_at=src_loc_at)
1360 self.lhs = Value.cast(lhs)
1361 self.rhs = Value.cast(rhs)
1362
1363 def _lhs_signals(self):
1364 return self.lhs._lhs_signals()
1365
1366 def _rhs_signals(self):
1367 return self.lhs._rhs_signals() | self.rhs._rhs_signals()
1368
1369 def __repr__(self):
1370 return "(eq {!r} {!r})".format(self.lhs, self.rhs)
1371
1372
1373 class UnusedProperty(UnusedMustUse):
1374 pass
1375
1376
1377 class Property(Statement, MustUse):
1378 _MustUse__warning = UnusedProperty
1379
1380 def __init__(self, test, *, _check=None, _en=None, src_loc_at=0):
1381 super().__init__(src_loc_at=src_loc_at)
1382 self.test = Value.cast(test)
1383 self._check = _check
1384 self._en = _en
1385 if self._check is None:
1386 self._check = Signal(reset_less=True, name="${}$check".format(self._kind))
1387 self._check.src_loc = self.src_loc
1388 if _en is None:
1389 self._en = Signal(reset_less=True, name="${}$en".format(self._kind))
1390 self._en.src_loc = self.src_loc
1391
1392 def _lhs_signals(self):
1393 return SignalSet((self._en, self._check))
1394
1395 def _rhs_signals(self):
1396 return self.test._rhs_signals()
1397
1398 def __repr__(self):
1399 return "({} {!r})".format(self._kind, self.test)
1400
1401
1402 @final
1403 class Assert(Property):
1404 _kind = "assert"
1405
1406
1407 @final
1408 class Assume(Property):
1409 _kind = "assume"
1410
1411
1412 @final
1413 class Cover(Property):
1414 _kind = "cover"
1415
1416
1417 # @final
1418 class Switch(Statement):
1419 def __init__(self, test, cases, *, src_loc=None, src_loc_at=0, case_src_locs={}):
1420 if src_loc is None:
1421 super().__init__(src_loc_at=src_loc_at)
1422 else:
1423 # Switch is a bit special in terms of location tracking because it is usually created
1424 # long after the control has left the statement that directly caused its creation.
1425 self.src_loc = src_loc
1426 # Switch is also a bit special in that its parts also have location information. It can't
1427 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1428 self.case_src_locs = {}
1429
1430 self.test = Value.cast(test)
1431 self.cases = OrderedDict()
1432 for orig_keys, stmts in cases.items():
1433 # Map: None -> (); key -> (key,); (key...) -> (key...)
1434 keys = orig_keys
1435 if keys is None:
1436 keys = ()
1437 if not isinstance(keys, tuple):
1438 keys = (keys,)
1439 # Map: 2 -> "0010"; "0010" -> "0010"
1440 new_keys = ()
1441 for key in keys:
1442 if isinstance(key, str):
1443 key = "".join(key.split()) # remove whitespace
1444 elif isinstance(key, int):
1445 key = format(key, "b").rjust(len(self.test), "0")
1446 elif isinstance(key, Enum):
1447 key = format(key.value, "b").rjust(len(self.test), "0")
1448 else:
1449 raise TypeError("Object {!r} cannot be used as a switch key"
1450 .format(key))
1451 assert len(key) == len(self.test)
1452 new_keys = (*new_keys, key)
1453 if not isinstance(stmts, Iterable):
1454 stmts = [stmts]
1455 self.cases[new_keys] = Statement.cast(stmts)
1456 if orig_keys in case_src_locs:
1457 self.case_src_locs[new_keys] = case_src_locs[orig_keys]
1458
1459 def _lhs_signals(self):
1460 signals = union((s._lhs_signals() for ss in self.cases.values() for s in ss),
1461 start=SignalSet())
1462 return signals
1463
1464 def _rhs_signals(self):
1465 signals = union((s._rhs_signals() for ss in self.cases.values() for s in ss),
1466 start=SignalSet())
1467 return self.test._rhs_signals() | signals
1468
1469 def __repr__(self):
1470 def case_repr(keys, stmts):
1471 stmts_repr = " ".join(map(repr, stmts))
1472 if keys == ():
1473 return "(default {})".format(stmts_repr)
1474 elif len(keys) == 1:
1475 return "(case {} {})".format(keys[0], stmts_repr)
1476 else:
1477 return "(case ({}) {})".format(" ".join(keys), stmts_repr)
1478 case_reprs = [case_repr(keys, stmts) for keys, stmts in self.cases.items()]
1479 return "(switch {!r} {})".format(self.test, " ".join(case_reprs))
1480
1481
1482 class _MappedKeyCollection(metaclass=ABCMeta):
1483 @abstractmethod
1484 def _map_key(self, key):
1485 pass # :nocov:
1486
1487 @abstractmethod
1488 def _unmap_key(self, key):
1489 pass # :nocov:
1490
1491
1492 class _MappedKeyDict(MutableMapping, _MappedKeyCollection):
1493 def __init__(self, pairs=()):
1494 self._storage = OrderedDict()
1495 for key, value in pairs:
1496 self[key] = value
1497
1498 def __getitem__(self, key):
1499 key = None if key is None else self._map_key(key)
1500 return self._storage[key]
1501
1502 def __setitem__(self, key, value):
1503 key = None if key is None else self._map_key(key)
1504 self._storage[key] = value
1505
1506 def __delitem__(self, key):
1507 key = None if key is None else self._map_key(key)
1508 del self._storage[key]
1509
1510 def __iter__(self):
1511 for key in self._storage:
1512 if key is None:
1513 yield None
1514 else:
1515 yield self._unmap_key(key)
1516
1517 def __eq__(self, other):
1518 if not isinstance(other, type(self)):
1519 return False
1520 if len(self) != len(other):
1521 return False
1522 for ak, bk in zip(sorted(self._storage), sorted(other._storage)):
1523 if ak != bk:
1524 return False
1525 if self._storage[ak] != other._storage[bk]:
1526 return False
1527 return True
1528
1529 def __len__(self):
1530 return len(self._storage)
1531
1532 def __repr__(self):
1533 pairs = ["({!r}, {!r})".format(k, v) for k, v in self.items()]
1534 return "{}.{}([{}])".format(type(self).__module__, type(self).__name__,
1535 ", ".join(pairs))
1536
1537
1538 class _MappedKeySet(MutableSet, _MappedKeyCollection):
1539 def __init__(self, elements=()):
1540 self._storage = OrderedDict()
1541 for elem in elements:
1542 self.add(elem)
1543
1544 def add(self, value):
1545 self._storage[self._map_key(value)] = None
1546
1547 def update(self, values):
1548 for value in values:
1549 self.add(value)
1550
1551 def discard(self, value):
1552 if value in self:
1553 del self._storage[self._map_key(value)]
1554
1555 def __contains__(self, value):
1556 return self._map_key(value) in self._storage
1557
1558 def __iter__(self):
1559 for key in [k for k in self._storage]:
1560 yield self._unmap_key(key)
1561
1562 def __len__(self):
1563 return len(self._storage)
1564
1565 def __repr__(self):
1566 return "{}.{}({})".format(type(self).__module__, type(self).__name__,
1567 ", ".join(repr(x) for x in self))
1568
1569
1570 class ValueKey:
1571 def __init__(self, value):
1572 self.value = Value.cast(value)
1573 if isinstance(self.value, Const):
1574 self._hash = hash(self.value.value)
1575 elif isinstance(self.value, (Signal, AnyValue)):
1576 self._hash = hash(self.value.duid)
1577 elif isinstance(self.value, (ClockSignal, ResetSignal)):
1578 self._hash = hash(self.value.domain)
1579 elif isinstance(self.value, Operator):
1580 self._hash = hash((self.value.operator,
1581 tuple(ValueKey(o) for o in self.value.operands)))
1582 elif isinstance(self.value, Slice):
1583 self._hash = hash((ValueKey(self.value.value), self.value.start, self.value.stop))
1584 elif isinstance(self.value, Part):
1585 self._hash = hash((ValueKey(self.value.value), ValueKey(self.value.offset),
1586 self.value.width, self.value.stride))
1587 elif isinstance(self.value, Cat):
1588 self._hash = hash(tuple(ValueKey(o) for o in self.value.parts))
1589 elif isinstance(self.value, ArrayProxy):
1590 self._hash = hash((ValueKey(self.value.index),
1591 tuple(ValueKey(e) for e in self.value._iter_as_values())))
1592 elif isinstance(self.value, Sample):
1593 self._hash = hash((ValueKey(self.value.value), self.value.clocks, self.value.domain))
1594 elif isinstance(self.value, Initial):
1595 self._hash = 0
1596 else: # :nocov:
1597 raise TypeError("Object {!r} cannot be used as a key in value collections"
1598 .format(self.value))
1599
1600 def __hash__(self):
1601 return self._hash
1602
1603 def __eq__(self, other):
1604 if type(other) is not ValueKey:
1605 return False
1606 if type(self.value) is not type(other.value):
1607 return False
1608
1609 if isinstance(self.value, Const):
1610 return self.value.value == other.value.value
1611 elif isinstance(self.value, (Signal, AnyValue)):
1612 return self.value is other.value
1613 elif isinstance(self.value, (ClockSignal, ResetSignal)):
1614 return self.value.domain == other.value.domain
1615 elif isinstance(self.value, Operator):
1616 return (self.value.operator == other.value.operator and
1617 len(self.value.operands) == len(other.value.operands) and
1618 all(ValueKey(a) == ValueKey(b)
1619 for a, b in zip(self.value.operands, other.value.operands)))
1620 elif isinstance(self.value, Slice):
1621 return (ValueKey(self.value.value) == ValueKey(other.value.value) and
1622 self.value.start == other.value.start and
1623 self.value.stop == other.value.stop)
1624 elif isinstance(self.value, Part):
1625 return (ValueKey(self.value.value) == ValueKey(other.value.value) and
1626 ValueKey(self.value.offset) == ValueKey(other.value.offset) and
1627 self.value.width == other.value.width and
1628 self.value.stride == other.value.stride)
1629 elif isinstance(self.value, Cat):
1630 return all(ValueKey(a) == ValueKey(b)
1631 for a, b in zip(self.value.parts, other.value.parts))
1632 elif isinstance(self.value, ArrayProxy):
1633 return (ValueKey(self.value.index) == ValueKey(other.value.index) and
1634 len(self.value.elems) == len(other.value.elems) and
1635 all(ValueKey(a) == ValueKey(b)
1636 for a, b in zip(self.value._iter_as_values(),
1637 other.value._iter_as_values())))
1638 elif isinstance(self.value, Sample):
1639 return (ValueKey(self.value.value) == ValueKey(other.value.value) and
1640 self.value.clocks == other.value.clocks and
1641 self.value.domain == self.value.domain)
1642 elif isinstance(self.value, Initial):
1643 return True
1644 else: # :nocov:
1645 raise TypeError("Object {!r} cannot be used as a key in value collections"
1646 .format(self.value))
1647
1648 def __lt__(self, other):
1649 if not isinstance(other, ValueKey):
1650 return False
1651 if type(self.value) != type(other.value):
1652 return False
1653
1654 if isinstance(self.value, Const):
1655 return self.value < other.value
1656 elif isinstance(self.value, (Signal, AnyValue)):
1657 return self.value.duid < other.value.duid
1658 elif isinstance(self.value, Slice):
1659 return (ValueKey(self.value.value) < ValueKey(other.value.value) and
1660 self.value.start < other.value.start and
1661 self.value.end < other.value.end)
1662 else: # :nocov:
1663 raise TypeError("Object {!r} cannot be used as a key in value collections")
1664
1665 def __repr__(self):
1666 return "<{}.ValueKey {!r}>".format(__name__, self.value)
1667
1668
1669 class ValueDict(_MappedKeyDict):
1670 _map_key = ValueKey
1671 _unmap_key = lambda self, key: key.value
1672
1673
1674 class ValueSet(_MappedKeySet):
1675 _map_key = ValueKey
1676 _unmap_key = lambda self, key: key.value
1677
1678
1679 class SignalKey:
1680 def __init__(self, signal):
1681 self.signal = signal
1682 if isinstance(signal, Signal):
1683 self._intern = (0, signal.duid)
1684 elif type(signal) is ClockSignal:
1685 self._intern = (1, signal.domain)
1686 elif type(signal) is ResetSignal:
1687 self._intern = (2, signal.domain)
1688 else:
1689 raise TypeError("Object {!r} is not an nMigen signal".format(signal))
1690
1691 def __hash__(self):
1692 return hash(self._intern)
1693
1694 def __eq__(self, other):
1695 if type(other) is not SignalKey:
1696 return False
1697 return self._intern == other._intern
1698
1699 def __lt__(self, other):
1700 if type(other) is not SignalKey:
1701 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal))
1702 return self._intern < other._intern
1703
1704 def __repr__(self):
1705 return "<{}.SignalKey {!r}>".format(__name__, self.signal)
1706
1707
1708 class SignalDict(_MappedKeyDict):
1709 _map_key = SignalKey
1710 _unmap_key = lambda self, key: key.signal
1711
1712
1713 class SignalSet(_MappedKeySet):
1714 _map_key = SignalKey
1715 _unmap_key = lambda self, key: key.signal