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