hdl.ast: deprecate UserValue in favor of ValueCastable.
[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 if b_signed:
706 extra = 2 ** (b_width - 1) - 1
707 else:
708 extra = 2 ** (b_width) - 1
709 return Shape(a_width + extra, a_signed)
710 if self.operator == ">>":
711 if b_signed:
712 extra = 2 ** (b_width - 1)
713 else:
714 extra = 0
715 return Shape(a_width + extra, a_signed)
716 elif len(op_shapes) == 3:
717 if self.operator == "m":
718 s_shape, a_shape, b_shape = op_shapes
719 return _bitwise_binary_shape(a_shape, b_shape)
720 raise NotImplementedError("Operator {}/{} not implemented"
721 .format(self.operator, len(op_shapes))) # :nocov:
722
723 def _rhs_signals(self):
724 return union(op._rhs_signals() for op in self.operands)
725
726 def __repr__(self):
727 return "({} {})".format(self.operator, " ".join(map(repr, self.operands)))
728
729
730 def Mux(sel, val1, val0):
731 """Choose between two values.
732
733 Parameters
734 ----------
735 sel : Value, in
736 Selector.
737 val1 : Value, in
738 val0 : Value, in
739 Input values.
740
741 Returns
742 -------
743 Value, out
744 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
745 """
746 sel = Value.cast(sel)
747 if len(sel) != 1:
748 sel = sel.bool()
749 return Operator("m", [sel, val1, val0])
750
751
752 @final
753 class Slice(Value):
754 def __init__(self, value, start, stop, *, src_loc_at=0):
755 if not isinstance(start, int):
756 raise TypeError("Slice start must be an integer, not {!r}".format(start))
757 if not isinstance(stop, int):
758 raise TypeError("Slice stop must be an integer, not {!r}".format(stop))
759
760 n = len(value)
761 if start not in range(-(n+1), n+1):
762 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start, n))
763 if start < 0:
764 start += n
765 if stop not in range(-(n+1), n+1):
766 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop, n))
767 if stop < 0:
768 stop += n
769 if start > stop:
770 raise IndexError("Slice start {} must be less than slice stop {}".format(start, stop))
771
772 super().__init__(src_loc_at=src_loc_at)
773 self.value = Value.cast(value)
774 self.start = start
775 self.stop = stop
776
777 def shape(self):
778 return Shape(self.stop - self.start)
779
780 def _lhs_signals(self):
781 return self.value._lhs_signals()
782
783 def _rhs_signals(self):
784 return self.value._rhs_signals()
785
786 def __repr__(self):
787 return "(slice {} {}:{})".format(repr(self.value), self.start, self.stop)
788
789
790 @final
791 class Part(Value):
792 def __init__(self, value, offset, width, stride=1, *, src_loc_at=0):
793 if not isinstance(width, int) or width < 0:
794 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width))
795 if not isinstance(stride, int) or stride <= 0:
796 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride))
797
798 super().__init__(src_loc_at=src_loc_at)
799 self.value = value
800 self.offset = Value.cast(offset)
801 self.width = width
802 self.stride = stride
803
804 def shape(self):
805 return Shape(self.width)
806
807 def _lhs_signals(self):
808 return self.value._lhs_signals()
809
810 def _rhs_signals(self):
811 return self.value._rhs_signals() | self.offset._rhs_signals()
812
813 def __repr__(self):
814 return "(part {} {} {} {})".format(repr(self.value), repr(self.offset),
815 self.width, self.stride)
816
817
818 @final
819 class Cat(Value):
820 """Concatenate values.
821
822 Form a compound ``Value`` from several smaller ones by concatenation.
823 The first argument occupies the lower bits of the result.
824 The return value can be used on either side of an assignment, that
825 is, the concatenated value can be used as an argument on the RHS or
826 as a target on the LHS. If it is used on the LHS, it must solely
827 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
828 meeting these properties. The bit length of the return value is the sum of
829 the bit lengths of the arguments::
830
831 len(Cat(args)) == sum(len(arg) for arg in args)
832
833 Parameters
834 ----------
835 *args : Values or iterables of Values, inout
836 ``Value`` s to be concatenated.
837
838 Returns
839 -------
840 Value, inout
841 Resulting ``Value`` obtained by concatentation.
842 """
843 def __init__(self, *args, src_loc_at=0):
844 super().__init__(src_loc_at=src_loc_at)
845 self.parts = [Value.cast(v) for v in flatten(args)]
846
847 def shape(self):
848 return Shape(sum(len(part) for part in self.parts))
849
850 def _lhs_signals(self):
851 return union((part._lhs_signals() for part in self.parts), start=SignalSet())
852
853 def _rhs_signals(self):
854 return union((part._rhs_signals() for part in self.parts), start=SignalSet())
855
856 def _as_const(self):
857 value = 0
858 for part in reversed(self.parts):
859 value <<= len(part)
860 value |= part._as_const()
861 return value
862
863 def __repr__(self):
864 return "(cat {})".format(" ".join(map(repr, self.parts)))
865
866
867 @final
868 class Repl(Value):
869 """Replicate a value
870
871 An input value is replicated (repeated) several times
872 to be used on the RHS of assignments::
873
874 len(Repl(s, n)) == len(s) * n
875
876 Parameters
877 ----------
878 value : Value, in
879 Input value to be replicated.
880 count : int
881 Number of replications.
882
883 Returns
884 -------
885 Repl, out
886 Replicated value.
887 """
888 def __init__(self, value, count, *, src_loc_at=0):
889 if not isinstance(count, int) or count < 0:
890 raise TypeError("Replication count must be a non-negative integer, not {!r}"
891 .format(count))
892
893 super().__init__(src_loc_at=src_loc_at)
894 self.value = Value.cast(value)
895 self.count = count
896
897 def shape(self):
898 return Shape(len(self.value) * self.count)
899
900 def _rhs_signals(self):
901 return self.value._rhs_signals()
902
903 def __repr__(self):
904 return "(repl {!r} {})".format(self.value, self.count)
905
906
907 # @final
908 class Signal(Value, DUID):
909 """A varying integer value.
910
911 Parameters
912 ----------
913 shape : ``Shape``-castable object or None
914 Specification for the number of bits in this ``Signal`` and its signedness (whether it
915 can represent negative values). See ``Shape.cast`` for details.
916 If not specified, ``shape`` defaults to 1-bit and non-signed.
917 name : str
918 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
919 name this ``Signal`` is assigned to.
920 reset : int or integral Enum
921 Reset (synchronous) or default (combinatorial) value.
922 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
923 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
924 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
925 assumes its ``reset`` value. Defaults to 0.
926 reset_less : bool
927 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
928 The ``reset`` value is only used as a combinatorial default or as the initial value.
929 Defaults to ``False``.
930 attrs : dict
931 Dictionary of synthesis attributes.
932 decoder : function or Enum
933 A function converting integer signal values to human-readable strings (e.g. FSM state
934 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
935 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
936 the enumeration.
937
938 Attributes
939 ----------
940 width : int
941 signed : bool
942 name : str
943 reset : int
944 reset_less : bool
945 attrs : dict
946 decoder : function
947 """
948
949 def __init__(self, shape=None, *, name=None, reset=0, reset_less=False,
950 attrs=None, decoder=None, src_loc_at=0):
951 super().__init__(src_loc_at=src_loc_at)
952
953 if name is not None and not isinstance(name, str):
954 raise TypeError("Name must be a string, not {!r}".format(name))
955 self.name = name or tracer.get_var_name(depth=2 + src_loc_at, default="$signal")
956
957 if shape is None:
958 shape = unsigned(1)
959 self.width, self.signed = Shape.cast(shape, src_loc_at=1 + src_loc_at)
960
961 if isinstance(reset, Enum):
962 reset = reset.value
963 if not isinstance(reset, int):
964 raise TypeError("Reset value has to be an int or an integral Enum")
965
966 reset_width = bits_for(reset, self.signed)
967 if reset != 0 and reset_width > self.width:
968 warnings.warn("Reset value {!r} requires {} bits to represent, but the signal "
969 "only has {} bits"
970 .format(reset, reset_width, self.width),
971 SyntaxWarning, stacklevel=2 + src_loc_at)
972
973 self.reset = reset
974 self.reset_less = bool(reset_less)
975
976 self.attrs = OrderedDict(() if attrs is None else attrs)
977
978 if decoder is None and isinstance(shape, type) and issubclass(shape, Enum):
979 decoder = shape
980 if isinstance(decoder, type) and issubclass(decoder, Enum):
981 def enum_decoder(value):
982 try:
983 return "{0.name:}/{0.value:}".format(decoder(value))
984 except ValueError:
985 return str(value)
986 self.decoder = enum_decoder
987 self._enum_class = decoder
988 else:
989 self.decoder = decoder
990 self._enum_class = None
991
992 # Not a @classmethod because nmigen.compat requires it.
993 @staticmethod
994 def like(other, *, name=None, name_suffix=None, src_loc_at=0, **kwargs):
995 """Create Signal based on another.
996
997 Parameters
998 ----------
999 other : Value
1000 Object to base this Signal on.
1001 """
1002 if name is not None:
1003 new_name = str(name)
1004 elif name_suffix is not None:
1005 new_name = other.name + str(name_suffix)
1006 else:
1007 new_name = tracer.get_var_name(depth=2 + src_loc_at, default="$like")
1008 kw = dict(shape=Value.cast(other).shape(), name=new_name)
1009 if isinstance(other, Signal):
1010 kw.update(reset=other.reset, reset_less=other.reset_less,
1011 attrs=other.attrs, decoder=other.decoder)
1012 kw.update(kwargs)
1013 return Signal(**kw, src_loc_at=1 + src_loc_at)
1014
1015 def shape(self):
1016 return Shape(self.width, self.signed)
1017
1018 def _lhs_signals(self):
1019 return SignalSet((self,))
1020
1021 def _rhs_signals(self):
1022 return SignalSet((self,))
1023
1024 def __repr__(self):
1025 return "(sig {})".format(self.name)
1026
1027
1028 @final
1029 class ClockSignal(Value):
1030 """Clock signal for a clock domain.
1031
1032 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
1033 All of these signals ultimately refer to the same signal, but they can be manipulated
1034 independently of the clock domain, even before the clock domain is created.
1035
1036 Parameters
1037 ----------
1038 domain : str
1039 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
1040 """
1041 def __init__(self, domain="sync", *, src_loc_at=0):
1042 super().__init__(src_loc_at=src_loc_at)
1043 if not isinstance(domain, str):
1044 raise TypeError("Clock domain name must be a string, not {!r}".format(domain))
1045 if domain == "comb":
1046 raise ValueError("Domain '{}' does not have a clock".format(domain))
1047 self.domain = domain
1048
1049 def shape(self):
1050 return Shape(1)
1051
1052 def _lhs_signals(self):
1053 return SignalSet((self,))
1054
1055 def _rhs_signals(self):
1056 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
1057
1058 def __repr__(self):
1059 return "(clk {})".format(self.domain)
1060
1061
1062 @final
1063 class ResetSignal(Value):
1064 """Reset signal for a clock domain.
1065
1066 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
1067 All of these signals ultimately refer to the same signal, but they can be manipulated
1068 independently of the clock domain, even before the clock domain is created.
1069
1070 Parameters
1071 ----------
1072 domain : str
1073 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
1074 allow_reset_less : bool
1075 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
1076 """
1077 def __init__(self, domain="sync", allow_reset_less=False, *, src_loc_at=0):
1078 super().__init__(src_loc_at=src_loc_at)
1079 if not isinstance(domain, str):
1080 raise TypeError("Clock domain name must be a string, not {!r}".format(domain))
1081 if domain == "comb":
1082 raise ValueError("Domain '{}' does not have a reset".format(domain))
1083 self.domain = domain
1084 self.allow_reset_less = allow_reset_less
1085
1086 def shape(self):
1087 return Shape(1)
1088
1089 def _lhs_signals(self):
1090 return SignalSet((self,))
1091
1092 def _rhs_signals(self):
1093 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
1094
1095 def __repr__(self):
1096 return "(rst {})".format(self.domain)
1097
1098
1099 class Array(MutableSequence):
1100 """Addressable multiplexer.
1101
1102 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
1103 in a proxy.
1104
1105 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
1106 assignments, provided that all elements of the array are values. The array proxy also supports
1107 attribute access and further indexing, each returning another array proxy; this means that
1108 the results of indexing into arrays, arrays of records, and arrays of arrays can all
1109 be used as first-class values.
1110
1111 It is an error to change an array or any of its elements after an array proxy was created.
1112 Changing the array directly will raise an exception. However, it is not possible to detect
1113 the elements being modified; if an element's attribute or element is modified after the proxy
1114 for it has been created, the proxy will refer to stale data.
1115
1116 Examples
1117 --------
1118
1119 Simple array::
1120
1121 gpios = Array(Signal() for _ in range(10))
1122 with m.If(bus.we):
1123 m.d.sync += gpios[bus.addr].eq(bus.w_data)
1124 with m.Else():
1125 m.d.sync += bus.r_data.eq(gpios[bus.addr])
1126
1127 Multidimensional array::
1128
1129 mult = Array(Array(x * y for y in range(10)) for x in range(10))
1130 a = Signal.range(10)
1131 b = Signal.range(10)
1132 r = Signal(8)
1133 m.d.comb += r.eq(mult[a][b])
1134
1135 Array of records::
1136
1137 layout = [
1138 ("r_data", 16),
1139 ("r_en", 1),
1140 ]
1141 buses = Array(Record(layout) for busno in range(4))
1142 master = Record(layout)
1143 m.d.comb += [
1144 buses[sel].r_en.eq(master.r_en),
1145 master.r_data.eq(buses[sel].r_data),
1146 ]
1147 """
1148 def __init__(self, iterable=()):
1149 self._inner = list(iterable)
1150 self._proxy_at = None
1151 self._mutable = True
1152
1153 def __getitem__(self, index):
1154 if isinstance(index, Value):
1155 if self._mutable:
1156 self._proxy_at = tracer.get_src_loc()
1157 self._mutable = False
1158 return ArrayProxy(self, index)
1159 else:
1160 return self._inner[index]
1161
1162 def __len__(self):
1163 return len(self._inner)
1164
1165 def _check_mutability(self):
1166 if not self._mutable:
1167 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1168 "at {}:{}".format(*self._proxy_at))
1169
1170 def __setitem__(self, index, value):
1171 self._check_mutability()
1172 self._inner[index] = value
1173
1174 def __delitem__(self, index):
1175 self._check_mutability()
1176 del self._inner[index]
1177
1178 def insert(self, index, value):
1179 self._check_mutability()
1180 self._inner.insert(index, value)
1181
1182 def __repr__(self):
1183 return "(array{} [{}])".format(" mutable" if self._mutable else "",
1184 ", ".join(map(repr, self._inner)))
1185
1186
1187 @final
1188 class ArrayProxy(Value):
1189 def __init__(self, elems, index, *, src_loc_at=0):
1190 super().__init__(src_loc_at=1 + src_loc_at)
1191 self.elems = elems
1192 self.index = Value.cast(index)
1193
1194 def __getattr__(self, attr):
1195 return ArrayProxy([getattr(elem, attr) for elem in self.elems], self.index)
1196
1197 def __getitem__(self, index):
1198 return ArrayProxy([ elem[index] for elem in self.elems], self.index)
1199
1200 def _iter_as_values(self):
1201 return (Value.cast(elem) for elem in self.elems)
1202
1203 def shape(self):
1204 unsigned_width = signed_width = 0
1205 has_unsigned = has_signed = False
1206 for elem_width, elem_signed in (elem.shape() for elem in self._iter_as_values()):
1207 if elem_signed:
1208 has_signed = True
1209 signed_width = max(signed_width, elem_width)
1210 else:
1211 has_unsigned = True
1212 unsigned_width = max(unsigned_width, elem_width)
1213 # The shape of the proxy must be such that it preserves the mathematical value of the array
1214 # elements. I.e., shape-wise, an array proxy must be identical to an equivalent mux tree.
1215 # To ensure this holds, if the array contains both signed and unsigned values, make sure
1216 # that every unsigned value is zero-extended by at least one bit.
1217 if has_signed and has_unsigned and unsigned_width >= signed_width:
1218 # Array contains both signed and unsigned values, and at least one of the unsigned
1219 # values won't be zero-extended otherwise.
1220 return signed(unsigned_width + 1)
1221 else:
1222 # Array contains values of the same signedness, or else all of the unsigned values
1223 # are zero-extended.
1224 return Shape(max(unsigned_width, signed_width), has_signed)
1225
1226 def _lhs_signals(self):
1227 signals = union((elem._lhs_signals() for elem in self._iter_as_values()),
1228 start=SignalSet())
1229 return signals
1230
1231 def _rhs_signals(self):
1232 signals = union((elem._rhs_signals() for elem in self._iter_as_values()),
1233 start=SignalSet())
1234 return self.index._rhs_signals() | signals
1235
1236 def __repr__(self):
1237 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self.elems)), self.index)
1238
1239
1240 # TODO(nmigen-0.4): remove
1241 class UserValue(Value):
1242 """Value with custom lowering.
1243
1244 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1245 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1246 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1247 value when required.
1248
1249 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1250 nMigen's view of representation of all values stays internally consistent. If the class
1251 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1252 it is not mutated in a way that changes its representation.
1253
1254 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1255 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1256 * Querying the shape using ``.shape()`` or ``len()``;
1257 * Creating a similarly shaped signal using ``Signal.like``;
1258 * Indexing or iterating through individual bits;
1259 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1260 """
1261 @deprecated("instead of `UserValue`, use `ValueCastable`", stacklevel=3)
1262 def __init__(self, *, src_loc_at=0):
1263 super().__init__(src_loc_at=1 + src_loc_at)
1264 self.__lowered = None
1265
1266 @abstractmethod
1267 def lower(self):
1268 """Conversion to a concrete representation."""
1269 pass # :nocov:
1270
1271 def _lazy_lower(self):
1272 if self.__lowered is None:
1273 lowered = self.lower()
1274 if isinstance(lowered, UserValue):
1275 lowered = lowered._lazy_lower()
1276 self.__lowered = Value.cast(lowered)
1277 return self.__lowered
1278
1279 def shape(self):
1280 return self._lazy_lower().shape()
1281
1282 def _lhs_signals(self):
1283 return self._lazy_lower()._lhs_signals()
1284
1285 def _rhs_signals(self):
1286 return self._lazy_lower()._rhs_signals()
1287
1288
1289 class ValueCastable:
1290 """Base class for classes which can be cast to Values.
1291
1292 A ``ValueCastable`` can be cast to ``Value``, meaning its precise representation does not have
1293 to be immediately known. This is useful in certain metaprogramming scenarios. Instead of
1294 providing fixed semantics upfront, it is kept abstract for as long as possible, only being
1295 cast to a concrete nMigen value when required.
1296
1297 Note that it is necessary to ensure that nMigen's view of representation of all values stays
1298 internally consistent. The class deriving from ``ValueCastable`` must decorate the ``as_value``
1299 method with the ``lowermethod`` decorator, which ensures that all calls to ``as_value``return the
1300 same ``Value`` representation. If the class deriving from ``ValueCastable`` is mutable, it is
1301 up to the user to ensure that it is not mutated in a way that changes its representation after
1302 the first call to ``as_value``.
1303 """
1304 def __new__(cls, *args, **kwargs):
1305 self = super().__new__(cls)
1306 if not hasattr(self, "as_value"):
1307 raise TypeError(f"Class '{cls.__name__}' deriving from `ValueCastable` must override the `as_value` method")
1308
1309 if not hasattr(self.as_value, "_ValueCastable__memoized"):
1310 raise TypeError(f"Class '{cls.__name__}' deriving from `ValueCastable` must decorate the `as_value` "
1311 "method with the `ValueCastable.lowermethod` decorator")
1312 return self
1313
1314 @staticmethod
1315 def lowermethod(func):
1316 """Decorator to memoize lowering methods.
1317
1318 Ensures the decorated method is called only once, with subsequent method calls returning the
1319 object returned by the first first method call.
1320
1321 This decorator is required to decorate the ``as_value`` method of ``ValueCastable`` subclasses.
1322 This is to ensure that nMigen's view of representation of all values stays internally
1323 consistent.
1324 """
1325 @functools.wraps(func)
1326 def wrapper_memoized(self, *args, **kwargs):
1327 if not hasattr(self, "_ValueCastable__lowered_to"):
1328 self.__lowered_to = func(self, *args, **kwargs)
1329 return self.__lowered_to
1330 wrapper_memoized.__memoized = True
1331 return wrapper_memoized
1332
1333
1334 @final
1335 class Sample(Value):
1336 """Value from the past.
1337
1338 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1339 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1340 to the value of the expression calculated as if each signal had its reset value.
1341 """
1342 def __init__(self, expr, clocks, domain, *, src_loc_at=0):
1343 super().__init__(src_loc_at=1 + src_loc_at)
1344 self.value = Value.cast(expr)
1345 self.clocks = int(clocks)
1346 self.domain = domain
1347 if not isinstance(self.value, (Const, Signal, ClockSignal, ResetSignal, Initial)):
1348 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1349 .format(self.value))
1350 if self.clocks < 0:
1351 raise ValueError("Cannot sample a value {} cycles in the future"
1352 .format(-self.clocks))
1353 if not (self.domain is None or isinstance(self.domain, str)):
1354 raise TypeError("Domain name must be a string or None, not {!r}"
1355 .format(self.domain))
1356
1357 def shape(self):
1358 return self.value.shape()
1359
1360 def _rhs_signals(self):
1361 return SignalSet((self,))
1362
1363 def __repr__(self):
1364 return "(sample {!r} @ {}[{}])".format(
1365 self.value, "<default>" if self.domain is None else self.domain, self.clocks)
1366
1367
1368 def Past(expr, clocks=1, domain=None):
1369 return Sample(expr, clocks, domain)
1370
1371
1372 def Stable(expr, clocks=0, domain=None):
1373 return Sample(expr, clocks + 1, domain) == Sample(expr, clocks, domain)
1374
1375
1376 def Rose(expr, clocks=0, domain=None):
1377 return ~Sample(expr, clocks + 1, domain) & Sample(expr, clocks, domain)
1378
1379
1380 def Fell(expr, clocks=0, domain=None):
1381 return Sample(expr, clocks + 1, domain) & ~Sample(expr, clocks, domain)
1382
1383
1384 @final
1385 class Initial(Value):
1386 """Start indicator, for model checking.
1387
1388 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1389 """
1390 def __init__(self, *, src_loc_at=0):
1391 super().__init__(src_loc_at=src_loc_at)
1392
1393 def shape(self):
1394 return Shape(1)
1395
1396 def _rhs_signals(self):
1397 return SignalSet((self,))
1398
1399 def __repr__(self):
1400 return "(initial)"
1401
1402
1403 class _StatementList(list):
1404 def __repr__(self):
1405 return "({})".format(" ".join(map(repr, self)))
1406
1407
1408 class Statement:
1409 def __init__(self, *, src_loc_at=0):
1410 self.src_loc = tracer.get_src_loc(1 + src_loc_at)
1411
1412 @staticmethod
1413 def cast(obj):
1414 if isinstance(obj, Iterable):
1415 return _StatementList(sum((Statement.cast(e) for e in obj), []))
1416 else:
1417 if isinstance(obj, Statement):
1418 return _StatementList([obj])
1419 else:
1420 raise TypeError("Object {!r} is not an nMigen statement".format(obj))
1421
1422
1423 @final
1424 class Assign(Statement):
1425 def __init__(self, lhs, rhs, *, src_loc_at=0):
1426 super().__init__(src_loc_at=src_loc_at)
1427 self.lhs = Value.cast(lhs)
1428 self.rhs = Value.cast(rhs)
1429
1430 def _lhs_signals(self):
1431 return self.lhs._lhs_signals()
1432
1433 def _rhs_signals(self):
1434 return self.lhs._rhs_signals() | self.rhs._rhs_signals()
1435
1436 def __repr__(self):
1437 return "(eq {!r} {!r})".format(self.lhs, self.rhs)
1438
1439
1440 class UnusedProperty(UnusedMustUse):
1441 pass
1442
1443
1444 class Property(Statement, MustUse):
1445 _MustUse__warning = UnusedProperty
1446
1447 def __init__(self, test, *, _check=None, _en=None, src_loc_at=0):
1448 super().__init__(src_loc_at=src_loc_at)
1449 self.test = Value.cast(test)
1450 self._check = _check
1451 self._en = _en
1452 if self._check is None:
1453 self._check = Signal(reset_less=True, name="${}$check".format(self._kind))
1454 self._check.src_loc = self.src_loc
1455 if _en is None:
1456 self._en = Signal(reset_less=True, name="${}$en".format(self._kind))
1457 self._en.src_loc = self.src_loc
1458
1459 def _lhs_signals(self):
1460 return SignalSet((self._en, self._check))
1461
1462 def _rhs_signals(self):
1463 return self.test._rhs_signals()
1464
1465 def __repr__(self):
1466 return "({} {!r})".format(self._kind, self.test)
1467
1468
1469 @final
1470 class Assert(Property):
1471 _kind = "assert"
1472
1473
1474 @final
1475 class Assume(Property):
1476 _kind = "assume"
1477
1478
1479 @final
1480 class Cover(Property):
1481 _kind = "cover"
1482
1483
1484 # @final
1485 class Switch(Statement):
1486 def __init__(self, test, cases, *, src_loc=None, src_loc_at=0, case_src_locs={}):
1487 if src_loc is None:
1488 super().__init__(src_loc_at=src_loc_at)
1489 else:
1490 # Switch is a bit special in terms of location tracking because it is usually created
1491 # long after the control has left the statement that directly caused its creation.
1492 self.src_loc = src_loc
1493 # Switch is also a bit special in that its parts also have location information. It can't
1494 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1495 self.case_src_locs = {}
1496
1497 self.test = Value.cast(test)
1498 self.cases = OrderedDict()
1499 for orig_keys, stmts in cases.items():
1500 # Map: None -> (); key -> (key,); (key...) -> (key...)
1501 keys = orig_keys
1502 if keys is None:
1503 keys = ()
1504 if not isinstance(keys, tuple):
1505 keys = (keys,)
1506 # Map: 2 -> "0010"; "0010" -> "0010"
1507 new_keys = ()
1508 for key in keys:
1509 if isinstance(key, str):
1510 key = "".join(key.split()) # remove whitespace
1511 elif isinstance(key, int):
1512 key = format(key, "b").rjust(len(self.test), "0")
1513 elif isinstance(key, Enum):
1514 key = format(key.value, "b").rjust(len(self.test), "0")
1515 else:
1516 raise TypeError("Object {!r} cannot be used as a switch key"
1517 .format(key))
1518 assert len(key) == len(self.test)
1519 new_keys = (*new_keys, key)
1520 if not isinstance(stmts, Iterable):
1521 stmts = [stmts]
1522 self.cases[new_keys] = Statement.cast(stmts)
1523 if orig_keys in case_src_locs:
1524 self.case_src_locs[new_keys] = case_src_locs[orig_keys]
1525
1526 def _lhs_signals(self):
1527 signals = union((s._lhs_signals() for ss in self.cases.values() for s in ss),
1528 start=SignalSet())
1529 return signals
1530
1531 def _rhs_signals(self):
1532 signals = union((s._rhs_signals() for ss in self.cases.values() for s in ss),
1533 start=SignalSet())
1534 return self.test._rhs_signals() | signals
1535
1536 def __repr__(self):
1537 def case_repr(keys, stmts):
1538 stmts_repr = " ".join(map(repr, stmts))
1539 if keys == ():
1540 return "(default {})".format(stmts_repr)
1541 elif len(keys) == 1:
1542 return "(case {} {})".format(keys[0], stmts_repr)
1543 else:
1544 return "(case ({}) {})".format(" ".join(keys), stmts_repr)
1545 case_reprs = [case_repr(keys, stmts) for keys, stmts in self.cases.items()]
1546 return "(switch {!r} {})".format(self.test, " ".join(case_reprs))
1547
1548
1549 class _MappedKeyCollection(metaclass=ABCMeta):
1550 @abstractmethod
1551 def _map_key(self, key):
1552 pass # :nocov:
1553
1554 @abstractmethod
1555 def _unmap_key(self, key):
1556 pass # :nocov:
1557
1558
1559 class _MappedKeyDict(MutableMapping, _MappedKeyCollection):
1560 def __init__(self, pairs=()):
1561 self._storage = OrderedDict()
1562 for key, value in pairs:
1563 self[key] = value
1564
1565 def __getitem__(self, key):
1566 key = None if key is None else self._map_key(key)
1567 return self._storage[key]
1568
1569 def __setitem__(self, key, value):
1570 key = None if key is None else self._map_key(key)
1571 self._storage[key] = value
1572
1573 def __delitem__(self, key):
1574 key = None if key is None else self._map_key(key)
1575 del self._storage[key]
1576
1577 def __iter__(self):
1578 for key in self._storage:
1579 if key is None:
1580 yield None
1581 else:
1582 yield self._unmap_key(key)
1583
1584 def __eq__(self, other):
1585 if not isinstance(other, type(self)):
1586 return False
1587 if len(self) != len(other):
1588 return False
1589 for ak, bk in zip(sorted(self._storage), sorted(other._storage)):
1590 if ak != bk:
1591 return False
1592 if self._storage[ak] != other._storage[bk]:
1593 return False
1594 return True
1595
1596 def __len__(self):
1597 return len(self._storage)
1598
1599 def __repr__(self):
1600 pairs = ["({!r}, {!r})".format(k, v) for k, v in self.items()]
1601 return "{}.{}([{}])".format(type(self).__module__, type(self).__name__,
1602 ", ".join(pairs))
1603
1604
1605 class _MappedKeySet(MutableSet, _MappedKeyCollection):
1606 def __init__(self, elements=()):
1607 self._storage = OrderedDict()
1608 for elem in elements:
1609 self.add(elem)
1610
1611 def add(self, value):
1612 self._storage[self._map_key(value)] = None
1613
1614 def update(self, values):
1615 for value in values:
1616 self.add(value)
1617
1618 def discard(self, value):
1619 if value in self:
1620 del self._storage[self._map_key(value)]
1621
1622 def __contains__(self, value):
1623 return self._map_key(value) in self._storage
1624
1625 def __iter__(self):
1626 for key in [k for k in self._storage]:
1627 yield self._unmap_key(key)
1628
1629 def __len__(self):
1630 return len(self._storage)
1631
1632 def __repr__(self):
1633 return "{}.{}({})".format(type(self).__module__, type(self).__name__,
1634 ", ".join(repr(x) for x in self))
1635
1636
1637 class ValueKey:
1638 def __init__(self, value):
1639 self.value = Value.cast(value)
1640 if isinstance(self.value, Const):
1641 self._hash = hash(self.value.value)
1642 elif isinstance(self.value, (Signal, AnyValue)):
1643 self._hash = hash(self.value.duid)
1644 elif isinstance(self.value, (ClockSignal, ResetSignal)):
1645 self._hash = hash(self.value.domain)
1646 elif isinstance(self.value, Operator):
1647 self._hash = hash((self.value.operator,
1648 tuple(ValueKey(o) for o in self.value.operands)))
1649 elif isinstance(self.value, Slice):
1650 self._hash = hash((ValueKey(self.value.value), self.value.start, self.value.stop))
1651 elif isinstance(self.value, Part):
1652 self._hash = hash((ValueKey(self.value.value), ValueKey(self.value.offset),
1653 self.value.width, self.value.stride))
1654 elif isinstance(self.value, Cat):
1655 self._hash = hash(tuple(ValueKey(o) for o in self.value.parts))
1656 elif isinstance(self.value, ArrayProxy):
1657 self._hash = hash((ValueKey(self.value.index),
1658 tuple(ValueKey(e) for e in self.value._iter_as_values())))
1659 elif isinstance(self.value, Sample):
1660 self._hash = hash((ValueKey(self.value.value), self.value.clocks, self.value.domain))
1661 elif isinstance(self.value, Initial):
1662 self._hash = 0
1663 else: # :nocov:
1664 raise TypeError("Object {!r} cannot be used as a key in value collections"
1665 .format(self.value))
1666
1667 def __hash__(self):
1668 return self._hash
1669
1670 def __eq__(self, other):
1671 if type(other) is not ValueKey:
1672 return False
1673 if type(self.value) is not type(other.value):
1674 return False
1675
1676 if isinstance(self.value, Const):
1677 return self.value.value == other.value.value
1678 elif isinstance(self.value, (Signal, AnyValue)):
1679 return self.value is other.value
1680 elif isinstance(self.value, (ClockSignal, ResetSignal)):
1681 return self.value.domain == other.value.domain
1682 elif isinstance(self.value, Operator):
1683 return (self.value.operator == other.value.operator and
1684 len(self.value.operands) == len(other.value.operands) and
1685 all(ValueKey(a) == ValueKey(b)
1686 for a, b in zip(self.value.operands, other.value.operands)))
1687 elif isinstance(self.value, Slice):
1688 return (ValueKey(self.value.value) == ValueKey(other.value.value) and
1689 self.value.start == other.value.start and
1690 self.value.stop == other.value.stop)
1691 elif isinstance(self.value, Part):
1692 return (ValueKey(self.value.value) == ValueKey(other.value.value) and
1693 ValueKey(self.value.offset) == ValueKey(other.value.offset) and
1694 self.value.width == other.value.width and
1695 self.value.stride == other.value.stride)
1696 elif isinstance(self.value, Cat):
1697 return all(ValueKey(a) == ValueKey(b)
1698 for a, b in zip(self.value.parts, other.value.parts))
1699 elif isinstance(self.value, ArrayProxy):
1700 return (ValueKey(self.value.index) == ValueKey(other.value.index) and
1701 len(self.value.elems) == len(other.value.elems) and
1702 all(ValueKey(a) == ValueKey(b)
1703 for a, b in zip(self.value._iter_as_values(),
1704 other.value._iter_as_values())))
1705 elif isinstance(self.value, Sample):
1706 return (ValueKey(self.value.value) == ValueKey(other.value.value) and
1707 self.value.clocks == other.value.clocks and
1708 self.value.domain == self.value.domain)
1709 elif isinstance(self.value, Initial):
1710 return True
1711 else: # :nocov:
1712 raise TypeError("Object {!r} cannot be used as a key in value collections"
1713 .format(self.value))
1714
1715 def __lt__(self, other):
1716 if not isinstance(other, ValueKey):
1717 return False
1718 if type(self.value) != type(other.value):
1719 return False
1720
1721 if isinstance(self.value, Const):
1722 return self.value < other.value
1723 elif isinstance(self.value, (Signal, AnyValue)):
1724 return self.value.duid < other.value.duid
1725 elif isinstance(self.value, Slice):
1726 return (ValueKey(self.value.value) < ValueKey(other.value.value) and
1727 self.value.start < other.value.start and
1728 self.value.end < other.value.end)
1729 else: # :nocov:
1730 raise TypeError("Object {!r} cannot be used as a key in value collections")
1731
1732 def __repr__(self):
1733 return "<{}.ValueKey {!r}>".format(__name__, self.value)
1734
1735
1736 class ValueDict(_MappedKeyDict):
1737 _map_key = ValueKey
1738 _unmap_key = lambda self, key: key.value
1739
1740
1741 class ValueSet(_MappedKeySet):
1742 _map_key = ValueKey
1743 _unmap_key = lambda self, key: key.value
1744
1745
1746 class SignalKey:
1747 def __init__(self, signal):
1748 self.signal = signal
1749 if isinstance(signal, Signal):
1750 self._intern = (0, signal.duid)
1751 elif type(signal) is ClockSignal:
1752 self._intern = (1, signal.domain)
1753 elif type(signal) is ResetSignal:
1754 self._intern = (2, signal.domain)
1755 else:
1756 raise TypeError("Object {!r} is not an nMigen signal".format(signal))
1757
1758 def __hash__(self):
1759 return hash(self._intern)
1760
1761 def __eq__(self, other):
1762 if type(other) is not SignalKey:
1763 return False
1764 return self._intern == other._intern
1765
1766 def __lt__(self, other):
1767 if type(other) is not SignalKey:
1768 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal))
1769 return self._intern < other._intern
1770
1771 def __repr__(self):
1772 return "<{}.SignalKey {!r}>".format(__name__, self.signal)
1773
1774
1775 class SignalDict(_MappedKeyDict):
1776 _map_key = SignalKey
1777 _unmap_key = lambda self, key: key.signal
1778
1779
1780 class SignalSet(_MappedKeySet):
1781 _map_key = SignalKey
1782 _unmap_key = lambda self, key: key.signal