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