1 from abc
import ABCMeta
, abstractmethod
4 from collections
import OrderedDict
5 from collections
.abc
import Iterable
, MutableMapping
, MutableSet
, MutableSequence
12 "Value", "Const", "C", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
13 "Array", "ArrayProxy",
14 "Signal", "ClockSignal", "ResetSignal",
15 "Statement", "Assign", "Switch", "Delay", "Tick", "Passive",
16 "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "SignalSet",
21 """Deterministic Unique IDentifier"""
24 self
.duid
= DUID
.__next
_uid
28 class Value(metaclass
=ABCMeta
):
31 """Ensures that the passed object is an nMigen value. Booleans and integers
32 are automatically wrapped into ``Const``."""
33 if isinstance(obj
, Value
):
35 elif isinstance(obj
, (bool, int)):
38 raise TypeError("Object '{!r}' is not an nMigen value".format(obj
))
40 def __init__(self
, src_loc_at
=0):
42 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
45 raise TypeError("Attempted to convert nMigen value to boolean")
48 return Operator("~", [self
])
50 return Operator("-", [self
])
52 def __add__(self
, other
):
53 return Operator("+", [self
, other
])
54 def __radd__(self
, other
):
55 return Operator("+", [other
, self
])
56 def __sub__(self
, other
):
57 return Operator("-", [self
, other
])
58 def __rsub__(self
, other
):
59 return Operator("-", [other
, self
])
60 def __mul__(self
, other
):
61 return Operator("*", [self
, other
])
62 def __rmul__(self
, other
):
63 return Operator("*", [other
, self
])
64 def __mod__(self
, other
):
65 return Operator("%", [self
, other
])
66 def __rmod__(self
, other
):
67 return Operator("%", [other
, self
])
68 def __div__(self
, other
):
69 return Operator("/", [self
, other
])
70 def __rdiv__(self
, other
):
71 return Operator("/", [other
, self
])
72 def __lshift__(self
, other
):
73 return Operator("<<", [self
, other
])
74 def __rlshift__(self
, other
):
75 return Operator("<<", [other
, self
])
76 def __rshift__(self
, other
):
77 return Operator(">>", [self
, other
])
78 def __rrshift__(self
, other
):
79 return Operator(">>", [other
, self
])
80 def __and__(self
, other
):
81 return Operator("&", [self
, other
])
82 def __rand__(self
, other
):
83 return Operator("&", [other
, self
])
84 def __xor__(self
, other
):
85 return Operator("^", [self
, other
])
86 def __rxor__(self
, other
):
87 return Operator("^", [other
, self
])
88 def __or__(self
, other
):
89 return Operator("|", [self
, other
])
90 def __ror__(self
, other
):
91 return Operator("|", [other
, self
])
93 def __eq__(self
, other
):
94 return Operator("==", [self
, other
])
95 def __ne__(self
, other
):
96 return Operator("!=", [self
, other
])
97 def __lt__(self
, other
):
98 return Operator("<", [self
, other
])
99 def __le__(self
, other
):
100 return Operator("<=", [self
, other
])
101 def __gt__(self
, other
):
102 return Operator(">", [self
, other
])
103 def __ge__(self
, other
):
104 return Operator(">=", [self
, other
])
107 return self
.shape()[0]
109 def __getitem__(self
, key
):
111 if isinstance(key
, int):
112 if key
not in range(-n
, n
):
113 raise IndexError("Cannot index {} bits into {}-bit value".format(key
, n
))
116 return Slice(self
, key
, key
+ 1)
117 elif isinstance(key
, slice):
118 start
, stop
, step
= key
.indices(n
)
120 return Cat(self
[i
] for i
in range(start
, stop
, step
))
121 return Slice(self
, start
, stop
)
123 raise TypeError("Cannot index value with {}".format(repr(key
)))
126 """Conversion to boolean.
131 Output ``Value``. If any bits are set, returns ``1``, else ``0``.
133 return Operator("b", [self
])
135 def part(self
, offset
, width
):
136 """Indexed part-select.
138 Selects a constant width but variable offset part of a ``Value``.
143 start point of the selected bits
145 number of selected bits
150 Selected part of the ``Value``
152 return Part(self
, offset
, width
)
160 Value to be assigned.
165 Assignment statement that can be used in combinatorial or synchronous context.
167 return Assign(self
, value
)
171 """Bit length and signedness of a value.
176 Number of bits required to store `v` or available in `v`, followed by
177 whether `v` has a sign bit (included in the bit count).
181 >>> Value.shape(Signal(8))
183 >>> Value.shape(C(0xaa))
188 def _lhs_signals(self
):
189 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
192 def _rhs_signals(self
):
199 """A constant, literal integer value.
204 shape : int or tuple or None
205 Either an integer `bits` or a tuple `(bits, signed)`
206 specifying the number of bits in this `Const` and whether it is
207 signed (can represent negative values). `shape` defaults
208 to the minimum width and signedness of `value`.
218 def normalize(value
, shape
):
219 nbits
, signed
= shape
220 mask
= (1 << nbits
) - 1
222 if signed
and value
>> (nbits
- 1):
226 def __init__(self
, value
, shape
=None):
227 self
.value
= int(value
)
229 shape
= bits_for(self
.value
), self
.value
< 0
230 if isinstance(shape
, int):
231 shape
= shape
, self
.value
< 0
232 self
.nbits
, self
.signed
= shape
233 if not isinstance(self
.nbits
, int) or self
.nbits
< 0:
234 raise TypeError("Width must be a non-negative integer, not '{!r}'", self
.nbits
)
235 self
.value
= self
.normalize(self
.value
, shape
)
238 return self
.nbits
, self
.signed
240 def _rhs_signals(self
):
244 return "(const {}'{}d{})".format(self
.nbits
, "s" if self
.signed
else "", self
.value
)
247 C
= Const
# shorthand
250 class Operator(Value
):
251 def __init__(self
, op
, operands
, src_loc_at
=0):
252 super().__init
__(src_loc_at
=1 + src_loc_at
)
254 self
.operands
= [Value
.wrap(o
) for o
in operands
]
257 def _bitwise_binary_shape(a_shape
, b_shape
):
258 a_bits
, a_sign
= a_shape
259 b_bits
, b_sign
= b_shape
260 if not a_sign
and not b_sign
:
261 # both operands unsigned
262 return max(a_bits
, b_bits
), False
263 elif a_sign
and b_sign
:
264 # both operands signed
265 return max(a_bits
, b_bits
), True
266 elif not a_sign
and b_sign
:
267 # first operand unsigned (add sign bit), second operand signed
268 return max(a_bits
+ 1, b_bits
), True
270 # first signed, second operand unsigned (add sign bit)
271 return max(a_bits
, b_bits
+ 1), True
274 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
275 if len(op_shapes
) == 1:
276 (a_bits
, a_sign
), = op_shapes
277 if self
.op
in ("+", "~"):
278 return a_bits
, a_sign
281 return a_bits
+ 1, True
283 return a_bits
, a_sign
286 elif len(op_shapes
) == 2:
287 (a_bits
, a_sign
), (b_bits
, b_sign
) = op_shapes
288 if self
.op
== "+" or self
.op
== "-":
289 bits
, sign
= self
._bitwise
_binary
_shape
(*op_shapes
)
290 return bits
+ 1, sign
292 if not a_sign
and not b_sign
:
293 # both operands unsigned
294 return a_bits
+ b_bits
, False
295 if a_sign
and b_sign
:
296 # both operands signed
297 return a_bits
+ b_bits
- 1, True
298 # one operand signed, the other unsigned (add sign bit)
299 return a_bits
+ b_bits
+ 1 - 1, True
300 if self
.op
in ("<", "<=", "==", "!=", ">", ">=", "b"):
302 if self
.op
in ("&", "^", "|"):
303 return self
._bitwise
_binary
_shape
(*op_shapes
)
306 extra
= 2 ** (b_bits
- 1) - 1
308 extra
= 2 ** (b_bits
) - 1
309 return a_bits
+ extra
, a_sign
312 extra
= 2 ** (b_bits
- 1)
315 return a_bits
+ extra
, a_sign
316 elif len(op_shapes
) == 3:
318 s_shape
, a_shape
, b_shape
= op_shapes
319 return self
._bitwise
_binary
_shape
(a_shape
, b_shape
)
320 raise NotImplementedError("Operator {}/{} not implemented"
321 .format(self
.op
, len(op_shapes
))) # :nocov:
323 def _rhs_signals(self
):
324 return union(op
._rhs
_signals
() for op
in self
.operands
)
327 return "({} {})".format(self
.op
, " ".join(map(repr, self
.operands
)))
330 def Mux(sel
, val1
, val0
):
331 """Choose between two values.
344 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
346 return Operator("m", [sel
, val1
, val0
], src_loc_at
=1)
350 def __init__(self
, value
, start
, end
):
351 if not isinstance(start
, int):
352 raise TypeError("Slice start must be an integer, not '{!r}'".format(start
))
353 if not isinstance(end
, int):
354 raise TypeError("Slice end must be an integer, not '{!r}'".format(end
))
357 if start
not in range(-n
, n
):
358 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
361 if end
not in range(-(n
+1), n
+1):
362 raise IndexError("Cannot end slice {} bits into {}-bit value".format(end
, n
))
366 raise IndexError("Slice start {} must be less than slice end {}".format(start
, end
))
369 self
.value
= Value
.wrap(value
)
374 return self
.end
- self
.start
, False
376 def _lhs_signals(self
):
377 return self
.value
._lhs
_signals
()
379 def _rhs_signals(self
):
380 return self
.value
._rhs
_signals
()
383 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.end
)
387 def __init__(self
, value
, offset
, width
):
388 if not isinstance(width
, int) or width
< 0:
389 raise TypeError("Part width must be a non-negative integer, not '{!r}'".format(width
))
393 self
.offset
= Value
.wrap(offset
)
397 return self
.width
, False
399 def _lhs_signals(self
):
400 return self
.value
._lhs
_signals
()
402 def _rhs_signals(self
):
403 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
406 return "(part {} {} {})".format(repr(self
.value
), repr(self
.offset
), self
.width
)
410 """Concatenate values.
412 Form a compound ``Value`` from several smaller ones by concatenation.
413 The first argument occupies the lower bits of the result.
414 The return value can be used on either side of an assignment, that
415 is, the concatenated value can be used as an argument on the RHS or
416 as a target on the LHS. If it is used on the LHS, it must solely
417 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
418 meeting these properties. The bit length of the return value is the sum of
419 the bit lengths of the arguments::
421 len(Cat(args)) == sum(len(arg) for arg in args)
425 *args : Values or iterables of Values, inout
426 ``Value`` s to be concatenated.
431 Resulting ``Value`` obtained by concatentation.
433 def __init__(self
, *args
):
435 self
.parts
= [Value
.wrap(v
) for v
in flatten(args
)]
438 return sum(len(op
) for op
in self
.parts
), False
440 def _lhs_signals(self
):
441 return union(op
._lhs
_signals
() for op
in self
.parts
)
443 def _rhs_signals(self
):
444 return union(op
._rhs
_signals
() for op
in self
.parts
)
447 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
453 An input value is replicated (repeated) several times
454 to be used on the RHS of assignments::
456 len(Repl(s, n)) == len(s) * n
461 Input value to be replicated.
463 Number of replications.
470 def __init__(self
, value
, count
):
471 if not isinstance(count
, int) or count
< 0:
472 raise TypeError("Replication count must be a non-negative integer, not '{!r}'"
476 self
.value
= Value
.wrap(value
)
480 return len(self
.value
) * self
.count
, False
482 def _rhs_signals(self
):
483 return self
.value
._rhs
_signals
()
486 return "(repl {!r} {})".format(self
.value
, self
.count
)
489 class Signal(Value
, DUID
):
490 """A varying integer value.
494 shape : int or tuple or None
495 Either an integer ``bits`` or a tuple ``(bits, signed)`` specifying the number of bits
496 in this ``Signal`` and whether it is signed (can represent negative values).
497 ``shape`` defaults to 1-bit and non-signed.
499 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
500 name this ``Signal`` is assigned to. Name collisions are automatically resolved by
501 prepending names of objects that contain this ``Signal`` and by appending integer
504 Reset (synchronous) or default (combinatorial) value.
505 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
506 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
507 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
508 assumes its ``reset`` value. Defaults to 0.
510 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
511 The ``reset`` value is only used as a combinatorial default or as the initial value.
512 Defaults to ``False``.
515 If ``shape`` is ``None``, the signal bit width and signedness are
516 determined by the integer range given by ``min`` (inclusive,
517 defaults to 0) and ``max`` (exclusive, defaults to 2).
519 Dictionary of synthesis attributes.
521 A function converting integer signal values to human-readable strings (e.g. FSM state
534 def __init__(self
, shape
=None, name
=None, reset
=0, reset_less
=False, min=None, max=None,
535 attrs
=None, decoder
=None, src_loc_at
=0):
536 super().__init
__(src_loc_at
=src_loc_at
)
540 name
= tracer
.get_var_name(depth
=2 + src_loc_at
)
541 except tracer
.NameNotFound
:
550 max -= 1 # make both bounds inclusive
552 raise ValueError("Lower bound {} should be less than higher bound {}"
554 self
.signed
= min < 0 or max < 0
555 self
.nbits
= builtins
.max(bits_for(min, self
.signed
), bits_for(max, self
.signed
))
558 if not (min is None and max is None):
559 raise ValueError("Only one of bits/signedness or bounds may be specified")
560 if isinstance(shape
, int):
561 self
.nbits
, self
.signed
= shape
, False
563 self
.nbits
, self
.signed
= shape
565 if not isinstance(self
.nbits
, int) or self
.nbits
< 0:
566 raise TypeError("Width must be a non-negative integer, not '{!r}'".format(self
.nbits
))
567 self
.reset
= int(reset
)
568 self
.reset_less
= bool(reset_less
)
570 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
571 self
.decoder
= decoder
574 def like(cls
, other
, src_loc_at
=0, **kwargs
):
575 """Create Signal based on another.
580 Object to base this Signal on.
582 kw
= dict(shape
=cls
.wrap(other
).shape(),
583 name
=tracer
.get_var_name(depth
=2 + src_loc_at
))
584 if isinstance(other
, cls
):
585 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
586 attrs
=other
.attrs
, decoder
=other
.decoder
)
588 return cls(**kw
, src_loc_at
=1 + src_loc_at
)
591 return self
.nbits
, self
.signed
593 def _lhs_signals(self
):
594 return ValueSet((self
,))
596 def _rhs_signals(self
):
597 return ValueSet((self
,))
600 return "(sig {})".format(self
.name
)
603 class ClockSignal(Value
):
604 """Clock signal for a clock domain.
606 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
607 All of these signals ultimately refer to the same signal, but they can be manipulated
608 independently of the clock domain, even before the clock domain is created.
613 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
615 def __init__(self
, domain
="sync"):
617 if not isinstance(domain
, str):
618 raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain
))
624 def _rhs_signals(self
):
625 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
628 return "(clk {})".format(self
.domain
)
631 class ResetSignal(Value
):
632 """Reset signal for a clock domain.
634 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
635 All of these signals ultimately refer to the same signal, but they can be manipulated
636 independently of the clock domain, even before the clock domain is created.
641 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
642 allow_reset_less : bool
643 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
645 def __init__(self
, domain
="sync", allow_reset_less
=False):
647 if not isinstance(domain
, str):
648 raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain
))
650 self
.allow_reset_less
= allow_reset_less
655 def _rhs_signals(self
):
656 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
659 return "(rst {})".format(self
.domain
)
662 class Array(MutableSequence
):
663 """Addressable multiplexer.
665 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
668 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
669 assignments, provided that all elements of the array are values. The array proxy also supports
670 attribute access and further indexing, each returning another array proxy; this means that
671 the results of indexing into arrays, arrays of records, and arrays of arrays can all
672 be used as first-class values.
674 It is an error to change an array or any of its elements after an array proxy was created.
675 Changing the array directly will raise an exception. However, it is not possible to detect
676 the elements being modified; if an element's attribute or element is modified after the proxy
677 for it has been created, the proxy will refer to stale data.
684 gpios = Array(Signal() for _ in range(10))
686 m.d.sync += gpios[bus.adr].eq(bus.dat_w)
688 m.d.sync += bus.dat_r.eq(gpios[bus.adr])
690 Multidimensional array::
692 mult = Array(Array(x * y for y in range(10)) for x in range(10))
696 m.d.comb += r.eq(mult[a][b])
704 buses = Array(Record(layout) for busno in range(4))
705 master = Record(layout)
707 buses[sel].re.eq(master.re),
708 master.dat_r.eq(buses[sel].dat_r),
711 def __init__(self
, iterable
=()):
712 self
._inner
= list(iterable
)
713 self
._proxy
_at
= None
716 def __getitem__(self
, index
):
717 if isinstance(index
, Value
):
719 self
._proxy
_at
= tracer
.get_src_loc()
720 self
._mutable
= False
721 return ArrayProxy(self
, index
)
723 return self
._inner
[index
]
726 return len(self
._inner
)
728 def _check_mutability(self
):
729 if not self
._mutable
:
730 raise ValueError("Array can no longer be mutated after it was indexed with a value "
731 "at {}:{}".format(*self
._proxy
_at
))
733 def __setitem__(self
, index
, value
):
734 self
._check
_mutability
()
735 self
._inner
[index
] = value
737 def __delitem__(self
, index
):
738 self
._check
_mutability
()
739 del self
._inner
[index
]
741 def insert(self
, index
, value
):
742 self
._check
_mutability
()
743 self
._inner
.insert(index
, value
)
746 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
747 ", ".join(map(repr, self
._inner
)))
750 class ArrayProxy(Value
):
751 def __init__(self
, elems
, index
):
752 super().__init
__(src_loc_at
=1)
754 self
.index
= Value
.wrap(index
)
756 def __getattr__(self
, attr
):
757 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
759 def __getitem__(self
, index
):
760 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
762 def _iter_as_values(self
):
763 return (Value
.wrap(elem
) for elem
in self
.elems
)
766 bits
, sign
= 0, False
767 for elem_bits
, elem_sign
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
768 bits
= max(bits
, elem_bits
+ elem_sign
)
769 sign
= max(sign
, elem_sign
)
772 def _lhs_signals(self
):
773 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()), start
=ValueSet())
776 def _rhs_signals(self
):
777 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()), start
=ValueSet())
778 return self
.index
._rhs
_signals
() | signals
781 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
784 class _StatementList(list):
786 return "({})".format(" ".join(map(repr, self
)))
792 if isinstance(obj
, Iterable
):
793 return _StatementList(sum((Statement
.wrap(e
) for e
in obj
), []))
795 if isinstance(obj
, Statement
):
796 return _StatementList([obj
])
798 raise TypeError("Object '{!r}' is not an nMigen statement".format(obj
))
801 class Assign(Statement
):
802 def __init__(self
, lhs
, rhs
):
803 self
.lhs
= Value
.wrap(lhs
)
804 self
.rhs
= Value
.wrap(rhs
)
806 def _lhs_signals(self
):
807 return self
.lhs
._lhs
_signals
()
809 def _rhs_signals(self
):
810 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
813 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
816 class Switch(Statement
):
817 def __init__(self
, test
, cases
):
818 self
.test
= Value
.wrap(test
)
819 self
.cases
= OrderedDict()
820 for key
, stmts
in cases
.items():
821 if isinstance(key
, (bool, int)):
822 key
= "{:0{}b}".format(key
, len(self
.test
))
823 elif isinstance(key
, str):
824 assert len(key
) == len(self
.test
)
826 raise TypeError("Object '{!r}' cannot be used as a switch key"
828 if not isinstance(stmts
, Iterable
):
830 self
.cases
[key
] = Statement
.wrap(stmts
)
832 def _lhs_signals(self
):
833 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
837 def _rhs_signals(self
):
838 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
840 return self
.test
._rhs
_signals
() | signals
843 cases
= ["(case {} {})".format(key
, " ".join(map(repr, stmts
)))
844 for key
, stmts
in self
.cases
.items()]
845 return "(switch {!r} {})".format(self
.test
, " ".join(cases
))
848 class Delay(Statement
):
849 def __init__(self
, interval
=None):
850 self
.interval
= None if interval
is None else float(interval
)
852 def _rhs_signals(self
):
856 if self
.interval
is None:
859 return "(delay {:.3}us)".format(self
.interval
* 10e6
)
862 class Tick(Statement
):
863 def __init__(self
, domain
):
864 self
.domain
= str(domain
)
866 def _rhs_signals(self
):
870 return "(tick {})".format(self
.domain
)
873 class Passive(Statement
):
874 def _rhs_signals(self
):
881 class _MappedKeyCollection(metaclass
=ABCMeta
):
883 def _map_key(self
, key
):
887 def _unmap_key(self
, key
):
891 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
892 def __init__(self
, pairs
=()):
893 self
._storage
= OrderedDict()
894 for key
, value
in pairs
:
897 def __getitem__(self
, key
):
898 key
= None if key
is None else self
._map
_key
(key
)
899 return self
._storage
[key
]
901 def __setitem__(self
, key
, value
):
902 key
= None if key
is None else self
._map
_key
(key
)
903 self
._storage
[key
] = value
905 def __delitem__(self
, key
):
906 key
= None if key
is None else self
._map
_key
(key
)
907 del self
._storage
[key
]
910 for key
in self
._storage
:
914 yield self
._unmap
_key
(key
)
916 def __eq__(self
, other
):
917 if not isinstance(other
, type(self
)):
919 if len(self
) != len(other
):
921 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
924 if self
._storage
[ak
] != other
._storage
[bk
]:
929 return len(self
._storage
)
932 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
933 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
937 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
938 def __init__(self
, elements
=()):
939 self
._storage
= OrderedDict()
940 for elem
in elements
:
943 def add(self
, value
):
944 self
._storage
[self
._map
_key
(value
)] = None
946 def update(self
, values
):
950 def discard(self
, value
):
952 del self
._storage
[self
._map
_key
(value
)]
954 def __contains__(self
, value
):
955 return self
._map
_key
(value
) in self
._storage
958 for key
in [k
for k
in self
._storage
]:
959 yield self
._unmap
_key
(key
)
962 return len(self
._storage
)
965 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
966 ", ".join(repr(x
) for x
in self
))
970 def __init__(self
, value
):
971 self
.value
= Value
.wrap(value
)
974 if isinstance(self
.value
, Const
):
975 return hash(self
.value
.value
)
976 elif isinstance(self
.value
, Signal
):
977 return hash(self
.value
.duid
)
978 elif isinstance(self
.value
, Operator
):
979 return hash((self
.value
.op
, tuple(ValueKey(o
) for o
in self
.value
.operands
)))
980 elif isinstance(self
.value
, Slice
):
981 return hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.end
))
982 elif isinstance(self
.value
, Part
):
983 return hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
985 elif isinstance(self
.value
, Cat
):
986 return hash(tuple(ValueKey(o
) for o
in self
.value
.operands
))
987 elif isinstance(self
.value
, ArrayProxy
):
988 return hash((ValueKey(self
.value
.index
),
989 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
991 raise TypeError("Object '{!r}' cannot be used as a key in value collections"
994 def __eq__(self
, other
):
995 if type(other
) is not ValueKey
:
997 if type(self
.value
) is not type(other
.value
):
1000 if isinstance(self
.value
, Const
):
1001 return self
.value
.value
== other
.value
.value
1002 elif isinstance(self
.value
, Signal
):
1003 return self
.value
is other
.value
1004 elif isinstance(self
.value
, Operator
):
1005 return (self
.value
.op
== other
.value
.op
and
1006 len(self
.value
.operands
) == len(other
.value
.operands
) and
1007 all(ValueKey(a
) == ValueKey(b
)
1008 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1009 elif isinstance(self
.value
, Slice
):
1010 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1011 self
.value
.start
== other
.value
.start
and
1012 self
.value
.end
== other
.value
.end
)
1013 elif isinstance(self
.value
, Part
):
1014 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1015 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1016 self
.value
.width
== other
.value
.width
)
1017 elif isinstance(self
.value
, Cat
):
1018 return all(ValueKey(a
) == ValueKey(b
)
1019 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
))
1020 elif isinstance(self
.value
, ArrayProxy
):
1021 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1022 len(self
.value
.elems
) == len(other
.value
.elems
) and
1023 all(ValueKey(a
) == ValueKey(b
)
1024 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1025 other
.value
._iter
_as
_values
())))
1027 raise TypeError("Object '{!r}' cannot be used as a key in value collections"
1028 .format(self
.value
))
1030 def __lt__(self
, other
):
1031 if not isinstance(other
, ValueKey
):
1033 if type(self
.value
) != type(other
.value
):
1036 if isinstance(self
.value
, Const
):
1037 return self
.value
< other
.value
1038 elif isinstance(self
.value
, Signal
):
1039 return self
.value
.duid
< other
.value
.duid
1040 elif isinstance(self
.value
, Slice
):
1041 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1042 self
.value
.start
< other
.value
.start
and
1043 self
.value
.end
< other
.value
.end
)
1045 raise TypeError("Object '{!r}' cannot be used as a key in value collections")
1048 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1051 class ValueDict(_MappedKeyDict
):
1053 _unmap_key
= lambda self
, key
: key
.value
1056 class ValueSet(_MappedKeySet
):
1058 _unmap_key
= lambda self
, key
: key
.value
1062 def __init__(self
, signal
):
1063 if type(signal
) is not Signal
:
1064 raise TypeError("Object '{!r}' is not an nMigen signal".format(signal
))
1065 self
.signal
= signal
1068 return hash(self
.signal
.duid
)
1070 def __eq__(self
, other
):
1071 if type(other
) is not SignalKey
:
1073 return self
.signal
is other
.signal
1075 def __lt__(self
, other
):
1076 if type(other
) is not SignalKey
:
1077 raise TypeError("Object '{!r}' cannot be compared to a SignalKey".format(signal
))
1078 return self
.signal
.duid
< other
.signal
.duid
1081 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1084 class SignalDict(_MappedKeyDict
):
1085 _map_key
= SignalKey
1086 _unmap_key
= lambda self
, key
: key
.signal
1089 class SignalSet(_MappedKeySet
):
1090 _map_key
= SignalKey
1091 _unmap_key
= lambda self
, key
: key
.signal