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