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