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