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):
43 tb
= traceback
.extract_stack(limit
=3 + src_loc_at
)
44 if len(tb
) < src_loc_at
:
47 self
.src_loc
= (tb
[0].filename
, tb
[0].lineno
)
50 raise TypeError("Attempted to convert nMigen value to boolean")
53 return Operator("~", [self
])
55 return Operator("-", [self
])
57 def __add__(self
, other
):
58 return Operator("+", [self
, other
])
59 def __radd__(self
, other
):
60 return Operator("+", [other
, self
])
61 def __sub__(self
, other
):
62 return Operator("-", [self
, other
])
63 def __rsub__(self
, other
):
64 return Operator("-", [other
, self
])
65 def __mul__(self
, other
):
66 return Operator("*", [self
, other
])
67 def __rmul__(self
, other
):
68 return Operator("*", [other
, self
])
69 def __mod__(self
, other
):
70 return Operator("%", [self
, other
])
71 def __rmod__(self
, other
):
72 return Operator("%", [other
, self
])
73 def __div__(self
, other
):
74 return Operator("/", [self
, other
])
75 def __rdiv__(self
, other
):
76 return Operator("/", [other
, self
])
77 def __lshift__(self
, other
):
78 return Operator("<<", [self
, other
])
79 def __rlshift__(self
, other
):
80 return Operator("<<", [other
, self
])
81 def __rshift__(self
, other
):
82 return Operator(">>", [self
, other
])
83 def __rrshift__(self
, other
):
84 return Operator(">>", [other
, self
])
85 def __and__(self
, other
):
86 return Operator("&", [self
, other
])
87 def __rand__(self
, other
):
88 return Operator("&", [other
, self
])
89 def __xor__(self
, other
):
90 return Operator("^", [self
, other
])
91 def __rxor__(self
, other
):
92 return Operator("^", [other
, self
])
93 def __or__(self
, other
):
94 return Operator("|", [self
, other
])
95 def __ror__(self
, other
):
96 return Operator("|", [other
, self
])
98 def __eq__(self
, other
):
99 return Operator("==", [self
, other
])
100 def __ne__(self
, other
):
101 return Operator("!=", [self
, other
])
102 def __lt__(self
, other
):
103 return Operator("<", [self
, other
])
104 def __le__(self
, other
):
105 return Operator("<=", [self
, other
])
106 def __gt__(self
, other
):
107 return Operator(">", [self
, other
])
108 def __ge__(self
, other
):
109 return Operator(">=", [self
, other
])
112 return self
.shape()[0]
114 def __getitem__(self
, key
):
116 if isinstance(key
, int):
117 if key
not in range(-n
, n
):
118 raise IndexError("Cannot index {} bits into {}-bit value".format(key
, n
))
121 return Slice(self
, key
, key
+ 1)
122 elif isinstance(key
, slice):
123 start
, stop
, step
= key
.indices(n
)
125 return Cat(self
[i
] for i
in range(start
, stop
, step
))
126 return Slice(self
, start
, stop
)
128 raise TypeError("Cannot index value with {}".format(repr(key
)))
131 """Conversion to boolean.
136 Output ``Value``. If any bits are set, returns ``1``, else ``0``.
138 return Operator("b", [self
])
140 def part(self
, offset
, width
):
141 """Indexed part-select.
143 Selects a constant width but variable offset part of a ``Value``.
148 start point of the selected bits
150 number of selected bits
155 Selected part of the ``Value``
157 return Part(self
, offset
, width
)
165 Value to be assigned.
170 Assignment statement that can be used in combinatorial or synchronous context.
172 return Assign(self
, value
)
176 """Bit length and signedness of a value.
181 Number of bits required to store `v` or available in `v`, followed by
182 whether `v` has a sign bit (included in the bit count).
186 >>> Value.shape(Signal(8))
188 >>> Value.shape(C(0xaa))
193 def _lhs_signals(self
):
194 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
197 def _rhs_signals(self
):
204 """A constant, literal integer value.
209 shape : int or tuple or None
210 Either an integer `bits` or a tuple `(bits, signed)`
211 specifying the number of bits in this `Const` and whether it is
212 signed (can represent negative values). `shape` defaults
213 to the minimum width and signedness of `value`.
223 def normalize(value
, shape
):
224 nbits
, signed
= shape
225 mask
= (1 << nbits
) - 1
227 if signed
and value
>> (nbits
- 1):
231 def __init__(self
, value
, shape
=None):
232 self
.value
= int(value
)
234 shape
= bits_for(self
.value
), self
.value
< 0
235 if isinstance(shape
, int):
236 shape
= shape
, self
.value
< 0
237 self
.nbits
, self
.signed
= shape
238 if not isinstance(self
.nbits
, int) or self
.nbits
< 0:
239 raise TypeError("Width must be a non-negative integer")
240 self
.value
= self
.normalize(self
.value
, shape
)
243 return self
.nbits
, self
.signed
245 def _rhs_signals(self
):
249 return "(const {}'{}d{})".format(self
.nbits
, "s" if self
.signed
else "", self
.value
)
252 C
= Const
# shorthand
255 class Operator(Value
):
256 def __init__(self
, op
, operands
, src_loc_at
=0):
257 super().__init
__(src_loc_at
=1 + src_loc_at
)
259 self
.operands
= [Value
.wrap(o
) for o
in operands
]
262 def _bitwise_binary_shape(a_shape
, b_shape
):
263 a_bits
, a_sign
= a_shape
264 b_bits
, b_sign
= b_shape
265 if not a_sign
and not b_sign
:
266 # both operands unsigned
267 return max(a_bits
, b_bits
), False
268 elif a_sign
and b_sign
:
269 # both operands signed
270 return max(a_bits
, b_bits
), True
271 elif not a_sign
and b_sign
:
272 # first operand unsigned (add sign bit), second operand signed
273 return max(a_bits
+ 1, b_bits
), True
275 # first signed, second operand unsigned (add sign bit)
276 return max(a_bits
, b_bits
+ 1), True
279 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
280 if len(op_shapes
) == 1:
281 (a_bits
, a_sign
), = op_shapes
282 if self
.op
in ("+", "~"):
283 return a_bits
, a_sign
286 return a_bits
+ 1, True
288 return a_bits
, a_sign
291 elif len(op_shapes
) == 2:
292 (a_bits
, a_sign
), (b_bits
, b_sign
) = op_shapes
293 if self
.op
== "+" or self
.op
== "-":
294 bits
, sign
= self
._bitwise
_binary
_shape
(*op_shapes
)
295 return bits
+ 1, sign
297 if not a_sign
and not b_sign
:
298 # both operands unsigned
299 return a_bits
+ b_bits
, False
300 if a_sign
and b_sign
:
301 # both operands signed
302 return a_bits
+ b_bits
- 1, True
303 # one operand signed, the other unsigned (add sign bit)
304 return a_bits
+ b_bits
+ 1 - 1, True
305 if self
.op
in ("<", "<=", "==", "!=", ">", ">=", "b"):
307 if self
.op
in ("&", "^", "|"):
308 return self
._bitwise
_binary
_shape
(*op_shapes
)
311 extra
= 2 ** (b_bits
- 1) - 1
313 extra
= 2 ** (b_bits
) - 1
314 return a_bits
+ extra
, a_sign
317 extra
= 2 ** (b_bits
- 1)
320 return a_bits
+ extra
, a_sign
321 elif len(op_shapes
) == 3:
323 s_shape
, a_shape
, b_shape
= op_shapes
324 return self
._bitwise
_binary
_shape
(a_shape
, b_shape
)
325 raise NotImplementedError("Operator {}/{} not implemented"
326 .format(self
.op
, len(op_shapes
))) # :nocov:
328 def _rhs_signals(self
):
329 return union(op
._rhs
_signals
() for op
in self
.operands
)
332 return "({} {})".format(self
.op
, " ".join(map(repr, self
.operands
)))
335 def Mux(sel
, val1
, val0
):
336 """Choose between two values.
349 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
351 return Operator("m", [sel
, val1
, val0
], src_loc_at
=1)
355 def __init__(self
, value
, start
, end
):
356 if not isinstance(start
, int):
357 raise TypeError("Slice start must be an integer, not '{!r}'".format(start
))
358 if not isinstance(end
, int):
359 raise TypeError("Slice end must be an integer, not '{!r}'".format(end
))
362 if start
not in range(-n
, n
):
363 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
366 if end
not in range(-(n
+1), n
+1):
367 raise IndexError("Cannot end slice {} bits into {}-bit value".format(end
, n
))
371 raise IndexError("Slice start {} must be less than slice end {}".format(start
, end
))
374 self
.value
= Value
.wrap(value
)
379 return self
.end
- self
.start
, False
381 def _lhs_signals(self
):
382 return self
.value
._lhs
_signals
()
384 def _rhs_signals(self
):
385 return self
.value
._rhs
_signals
()
388 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.end
)
392 def __init__(self
, value
, offset
, width
):
393 if not isinstance(width
, int) or width
< 0:
394 raise TypeError("Part width must be a non-negative integer, not '{!r}'".format(width
))
398 self
.offset
= Value
.wrap(offset
)
402 return self
.width
, False
404 def _lhs_signals(self
):
405 return self
.value
._lhs
_signals
()
407 def _rhs_signals(self
):
408 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
411 return "(part {} {} {})".format(repr(self
.value
), repr(self
.offset
), self
.width
)
415 """Concatenate values.
417 Form a compound ``Value`` from several smaller ones by concatenation.
418 The first argument occupies the lower bits of the result.
419 The return value can be used on either side of an assignment, that
420 is, the concatenated value can be used as an argument on the RHS or
421 as a target on the LHS. If it is used on the LHS, it must solely
422 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
423 meeting these properties. The bit length of the return value is the sum of
424 the bit lengths of the arguments::
426 len(Cat(args)) == sum(len(arg) for arg in args)
430 *args : Values or iterables of Values, inout
431 ``Value`` s to be concatenated.
436 Resulting ``Value`` obtained by concatentation.
438 def __init__(self
, *args
):
440 self
.parts
= [Value
.wrap(v
) for v
in flatten(args
)]
443 return sum(len(op
) for op
in self
.parts
), False
445 def _lhs_signals(self
):
446 return union(op
._lhs
_signals
() for op
in self
.parts
)
448 def _rhs_signals(self
):
449 return union(op
._rhs
_signals
() for op
in self
.parts
)
452 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
458 An input value is replicated (repeated) several times
459 to be used on the RHS of assignments::
461 len(Repl(s, n)) == len(s) * n
466 Input value to be replicated.
468 Number of replications.
475 def __init__(self
, value
, count
):
476 if not isinstance(count
, int) or count
< 0:
477 raise TypeError("Replication count must be a non-negative integer, not '{!r}'"
481 self
.value
= Value
.wrap(value
)
485 return len(self
.value
) * self
.count
, False
487 def _rhs_signals(self
):
488 return self
.value
._rhs
_signals
()
491 return "(repl {!r} {})".format(self
.value
, self
.count
)
494 class Signal(Value
, DUID
):
495 """A varying integer value.
499 shape : int or tuple or None
500 Either an integer ``bits`` or a tuple ``(bits, signed)`` specifying the number of bits
501 in this ``Signal`` and whether it is signed (can represent negative values).
502 ``shape`` defaults to 1-bit and non-signed.
504 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
505 name this ``Signal`` is assigned to. Name collisions are automatically resolved by
506 prepending names of objects that contain this ``Signal`` and by appending integer
509 Reset (synchronous) or default (combinatorial) value.
510 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
511 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
512 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
513 assumes its ``reset`` value. Defaults to 0.
515 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
516 The ``reset`` value is only used as a combinatorial default or as the initial value.
517 Defaults to ``False``.
520 If ``shape`` is ``None``, the signal bit width and signedness are
521 determined by the integer range given by ``min`` (inclusive,
522 defaults to 0) and ``max`` (exclusive, defaults to 2).
524 Dictionary of synthesis attributes.
526 A function converting integer signal values to human-readable strings (e.g. FSM state
539 def __init__(self
, shape
=None, name
=None, reset
=0, reset_less
=False, min=None, max=None,
540 attrs
=None, decoder
=None, src_loc_at
=0):
541 super().__init
__(src_loc_at
=src_loc_at
)
545 name
= tracer
.get_var_name(depth
=2 + src_loc_at
)
546 except tracer
.NameNotFound
:
555 max -= 1 # make both bounds inclusive
557 raise ValueError("Lower bound {} should be less than higher bound {}"
559 self
.signed
= min < 0 or max < 0
560 self
.nbits
= builtins
.max(bits_for(min, self
.signed
), bits_for(max, self
.signed
))
563 if not (min is None and max is None):
564 raise ValueError("Only one of bits/signedness or bounds may be specified")
565 if isinstance(shape
, int):
566 self
.nbits
, self
.signed
= shape
, False
568 self
.nbits
, self
.signed
= shape
570 if not isinstance(self
.nbits
, int) or self
.nbits
< 0:
571 raise TypeError("Width must be a non-negative integer, not '{!r}'".format(self
.nbits
))
572 self
.reset
= int(reset
)
573 self
.reset_less
= bool(reset_less
)
575 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
576 self
.decoder
= decoder
579 def like(cls
, other
, src_loc_at
=0, **kwargs
):
580 """Create Signal based on another.
585 Object to base this Signal on.
587 kw
= dict(shape
=cls
.wrap(other
).shape(),
588 name
=tracer
.get_var_name(depth
=2 + src_loc_at
))
589 if isinstance(other
, cls
):
590 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
591 attrs
=other
.attrs
, decoder
=other
.decoder
)
593 return cls(**kw
, src_loc_at
=1 + src_loc_at
)
596 return self
.nbits
, self
.signed
598 def _lhs_signals(self
):
599 return ValueSet((self
,))
601 def _rhs_signals(self
):
602 return ValueSet((self
,))
605 return "(sig {})".format(self
.name
)
608 class ClockSignal(Value
):
609 """Clock signal for a clock domain.
611 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
612 All of these signals ultimately refer to the same signal, but they can be manipulated
613 independently of the clock domain, even before the clock domain is created.
618 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
620 def __init__(self
, domain
="sync"):
622 if not isinstance(domain
, str):
623 raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain
))
629 def _rhs_signals(self
):
630 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
633 return "(clk {})".format(self
.domain
)
636 class ResetSignal(Value
):
637 """Reset signal for a clock domain.
639 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
640 All of these signals ultimately refer to the same signal, but they can be manipulated
641 independently of the clock domain, even before the clock domain is created.
646 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
647 allow_reset_less : bool
648 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
650 def __init__(self
, domain
="sync", allow_reset_less
=False):
652 if not isinstance(domain
, str):
653 raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain
))
655 self
.allow_reset_less
= allow_reset_less
660 def _rhs_signals(self
):
661 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
664 return "(rst {})".format(self
.domain
)
667 class Array(MutableSequence
):
668 """Addressable multiplexer.
670 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
673 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
674 assignments, provided that all elements of the array are values. The array proxy also supports
675 attribute access and further indexing, each returning another array proxy; this means that
676 the results of indexing into arrays, arrays of records, and arrays of arrays can all
677 be used as first-class values.
679 It is an error to change an array or any of its elements after an array proxy was created.
680 Changing the array directly will raise an exception. However, it is not possible to detect
681 the elements being modified; if an element's attribute or element is modified after the proxy
682 for it has been created, the proxy will refer to stale data.
689 gpios = Array(Signal() for _ in range(10))
691 m.d.sync += gpios[bus.adr].eq(bus.dat_w)
693 m.d.sync += bus.dat_r.eq(gpios[bus.adr])
695 Multidimensional array::
697 mult = Array(Array(x * y for y in range(10)) for x in range(10))
701 m.d.comb += r.eq(mult[a][b])
709 buses = Array(Record(layout) for busno in range(4))
710 master = Record(layout)
712 buses[sel].re.eq(master.re),
713 master.dat_r.eq(buses[sel].dat_r),
716 def __init__(self
, iterable
=()):
717 self
._inner
= list(iterable
)
718 self
._proxy
_at
= None
721 def __getitem__(self
, index
):
722 if isinstance(index
, Value
):
724 tb
= traceback
.extract_stack(limit
=2)
725 self
._proxy
_at
= (tb
[0].filename
, tb
[0].lineno
)
726 self
._mutable
= False
727 return ArrayProxy(self
, index
)
729 return self
._inner
[index
]
732 return len(self
._inner
)
734 def _check_mutability(self
):
735 if not self
._mutable
:
736 raise ValueError("Array can no longer be mutated after it was indexed with a value "
737 "at {}:{}".format(*self
._proxy
_at
))
739 def __setitem__(self
, index
, value
):
740 self
._check
_mutability
()
741 self
._inner
[index
] = value
743 def __delitem__(self
, index
):
744 self
._check
_mutability
()
745 del self
._inner
[index
]
747 def insert(self
, index
, value
):
748 self
._check
_mutability
()
749 self
._inner
.insert(index
, value
)
752 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
753 ", ".join(map(repr, self
._inner
)))
756 class ArrayProxy(Value
):
757 def __init__(self
, elems
, index
):
758 super().__init
__(src_loc_at
=1)
760 self
.index
= Value
.wrap(index
)
762 def __getattr__(self
, attr
):
763 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
765 def __getitem__(self
, index
):
766 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
768 def _iter_as_values(self
):
769 return (Value
.wrap(elem
) for elem
in self
.elems
)
772 bits
, sign
= 0, False
773 for elem_bits
, elem_sign
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
774 bits
= max(bits
, elem_bits
+ elem_sign
)
775 sign
= max(sign
, elem_sign
)
778 def _lhs_signals(self
):
779 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()), start
=ValueSet())
782 def _rhs_signals(self
):
783 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()), start
=ValueSet())
784 return self
.index
._rhs
_signals
() | signals
787 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
790 class _StatementList(list):
792 return "({})".format(" ".join(map(repr, self
)))
798 if isinstance(obj
, Iterable
):
799 return _StatementList(sum((Statement
.wrap(e
) for e
in obj
), []))
801 if isinstance(obj
, Statement
):
802 return _StatementList([obj
])
804 raise TypeError("Object '{!r}' is not an nMigen statement".format(obj
))
807 class Assign(Statement
):
808 def __init__(self
, lhs
, rhs
):
809 self
.lhs
= Value
.wrap(lhs
)
810 self
.rhs
= Value
.wrap(rhs
)
812 def _lhs_signals(self
):
813 return self
.lhs
._lhs
_signals
()
815 def _rhs_signals(self
):
816 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
819 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
822 class Switch(Statement
):
823 def __init__(self
, test
, cases
):
824 self
.test
= Value
.wrap(test
)
825 self
.cases
= OrderedDict()
826 for key
, stmts
in cases
.items():
827 if isinstance(key
, (bool, int)):
828 key
= "{:0{}b}".format(key
, len(self
.test
))
829 elif isinstance(key
, str):
830 assert len(key
) == len(self
.test
)
832 raise TypeError("Object '{!r}' cannot be used as a switch key"
834 if not isinstance(stmts
, Iterable
):
836 self
.cases
[key
] = Statement
.wrap(stmts
)
838 def _lhs_signals(self
):
839 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
843 def _rhs_signals(self
):
844 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
846 return self
.test
._rhs
_signals
() | signals
849 cases
= ["(case {} {})".format(key
, " ".join(map(repr, stmts
)))
850 for key
, stmts
in self
.cases
.items()]
851 return "(switch {!r} {})".format(self
.test
, " ".join(cases
))
854 class Delay(Statement
):
855 def __init__(self
, interval
=None):
856 self
.interval
= None if interval
is None else float(interval
)
858 def _rhs_signals(self
):
862 if self
.interval
is None:
865 return "(delay {:.3}us)".format(self
.interval
* 10e6
)
868 class Tick(Statement
):
869 def __init__(self
, domain
):
870 self
.domain
= str(domain
)
872 def _rhs_signals(self
):
876 return "(tick {})".format(self
.domain
)
879 class Passive(Statement
):
880 def _rhs_signals(self
):
887 class _MappedKeyCollection(metaclass
=ABCMeta
):
889 def _map_key(self
, key
):
893 def _unmap_key(self
, key
):
897 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
898 def __init__(self
, pairs
=()):
899 self
._storage
= OrderedDict()
900 for key
, value
in pairs
:
903 def __getitem__(self
, key
):
904 key
= None if key
is None else self
._map
_key
(key
)
905 return self
._storage
[key
]
907 def __setitem__(self
, key
, value
):
908 key
= None if key
is None else self
._map
_key
(key
)
909 self
._storage
[key
] = value
911 def __delitem__(self
, key
):
912 key
= None if key
is None else self
._map
_key
(key
)
913 del self
._storage
[key
]
916 for key
in self
._storage
:
920 yield self
._unmap
_key
(key
)
922 def __eq__(self
, other
):
923 if not isinstance(other
, type(self
)):
925 if len(self
) != len(other
):
927 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
930 if self
._storage
[ak
] != other
._storage
[bk
]:
935 return len(self
._storage
)
938 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
939 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
943 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
944 def __init__(self
, elements
=()):
945 self
._storage
= OrderedDict()
946 for elem
in elements
:
949 def add(self
, value
):
950 self
._storage
[self
._map
_key
(value
)] = None
952 def update(self
, values
):
956 def discard(self
, value
):
958 del self
._storage
[self
._map
_key
(value
)]
960 def __contains__(self
, value
):
961 return self
._map
_key
(value
) in self
._storage
964 for key
in [k
for k
in self
._storage
]:
965 yield self
._unmap
_key
(key
)
968 return len(self
._storage
)
971 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
972 ", ".join(repr(x
) for x
in self
))
976 def __init__(self
, value
):
977 self
.value
= Value
.wrap(value
)
980 if isinstance(self
.value
, Const
):
981 return hash(self
.value
.value
)
982 elif isinstance(self
.value
, Signal
):
983 return hash(self
.value
.duid
)
984 elif isinstance(self
.value
, Operator
):
985 return hash((self
.value
.op
, tuple(ValueKey(o
) for o
in self
.value
.operands
)))
986 elif isinstance(self
.value
, Slice
):
987 return hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.end
))
988 elif isinstance(self
.value
, Part
):
989 return hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
991 elif isinstance(self
.value
, Cat
):
992 return hash(tuple(ValueKey(o
) for o
in self
.value
.operands
))
993 elif isinstance(self
.value
, ArrayProxy
):
994 return hash((ValueKey(self
.value
.index
),
995 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
997 raise TypeError("Object '{!r}' cannot be used as a key in value collections"
1000 def __eq__(self
, other
):
1001 if type(other
) is not ValueKey
:
1003 if type(self
.value
) is not type(other
.value
):
1006 if isinstance(self
.value
, Const
):
1007 return self
.value
.value
== other
.value
.value
1008 elif isinstance(self
.value
, Signal
):
1009 return self
.value
is other
.value
1010 elif isinstance(self
.value
, Operator
):
1011 return (self
.value
.op
== other
.value
.op
and
1012 len(self
.value
.operands
) == len(other
.value
.operands
) and
1013 all(ValueKey(a
) == ValueKey(b
)
1014 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1015 elif isinstance(self
.value
, Slice
):
1016 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1017 self
.value
.start
== other
.value
.start
and
1018 self
.value
.end
== other
.value
.end
)
1019 elif isinstance(self
.value
, Part
):
1020 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1021 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1022 self
.value
.width
== other
.value
.width
)
1023 elif isinstance(self
.value
, Cat
):
1024 return all(ValueKey(a
) == ValueKey(b
)
1025 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
))
1026 elif isinstance(self
.value
, ArrayProxy
):
1027 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1028 len(self
.value
.elems
) == len(other
.value
.elems
) and
1029 all(ValueKey(a
) == ValueKey(b
)
1030 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1031 other
.value
._iter
_as
_values
())))
1033 raise TypeError("Object '{!r}' cannot be used as a key in value collections"
1034 .format(self
.value
))
1036 def __lt__(self
, other
):
1037 if not isinstance(other
, ValueKey
):
1039 if type(self
.value
) != type(other
.value
):
1042 if isinstance(self
.value
, Const
):
1043 return self
.value
< other
.value
1044 elif isinstance(self
.value
, Signal
):
1045 return self
.value
.duid
< other
.value
.duid
1046 elif isinstance(self
.value
, Slice
):
1047 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1048 self
.value
.start
< other
.value
.start
and
1049 self
.value
.end
< other
.value
.end
)
1051 raise TypeError("Object '{!r}' cannot be used as a key in value collections")
1054 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1057 class ValueDict(_MappedKeyDict
):
1059 _unmap_key
= lambda self
, key
: key
.value
1062 class ValueSet(_MappedKeySet
):
1064 _unmap_key
= lambda self
, key
: key
.value
1068 def __init__(self
, signal
):
1069 if type(signal
) is not Signal
:
1070 raise TypeError("Object '{!r}' is not an nMigen signal")
1071 self
.signal
= signal
1074 return hash(self
.signal
.duid
)
1076 def __eq__(self
, other
):
1077 if type(other
) is not SignalKey
:
1079 return self
.signal
is other
.signal
1081 def __lt__(self
, other
):
1082 if type(other
) is not SignalKey
:
1083 raise TypeError("Object '{!r}' cannot be compared to a SignalKey")
1084 return self
.signal
.duid
< other
.signal
.duid
1087 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1090 class SignalDict(_MappedKeyDict
):
1091 _map_key
= SignalKey
1092 _unmap_key
= lambda self
, key
: key
.signal
1095 class SignalSet(_MappedKeySet
):
1096 _map_key
= SignalKey
1097 _unmap_key
= lambda self
, key
: key
.signal