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