1 from abc
import ABCMeta
, abstractmethod
4 from collections
import OrderedDict
5 from collections
.abc
import Iterable
, MutableMapping
, MutableSet
, MutableSequence
12 "Value", "Const", "C", "AnyConst", "AnySeq", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
13 "Array", "ArrayProxy",
14 "Sample", "Past", "Stable", "Rose", "Fell",
15 "Signal", "ClockSignal", "ResetSignal",
17 "Statement", "Assign", "Assert", "Assume", "Switch", "Delay", "Tick",
18 "Passive", "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict",
24 """Deterministic Unique IDentifier"""
27 self
.duid
= DUID
.__next
_uid
31 class Value(metaclass
=ABCMeta
):
34 """Ensures that the passed object is an nMigen value. Booleans and integers
35 are automatically wrapped into ``Const``."""
36 if isinstance(obj
, Value
):
38 elif isinstance(obj
, (bool, int)):
41 raise TypeError("Object '{!r}' is not an nMigen value".format(obj
))
43 def __init__(self
, src_loc_at
=0):
45 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
48 raise TypeError("Attempted to convert nMigen value to boolean")
51 return Operator("~", [self
])
53 return Operator("-", [self
])
55 def __add__(self
, other
):
56 return Operator("+", [self
, other
])
57 def __radd__(self
, other
):
58 return Operator("+", [other
, self
])
59 def __sub__(self
, other
):
60 return Operator("-", [self
, other
])
61 def __rsub__(self
, other
):
62 return Operator("-", [other
, self
])
63 def __mul__(self
, other
):
64 return Operator("*", [self
, other
])
65 def __rmul__(self
, other
):
66 return Operator("*", [other
, self
])
67 def __mod__(self
, other
):
68 return Operator("%", [self
, other
])
69 def __rmod__(self
, other
):
70 return Operator("%", [other
, self
])
71 def __div__(self
, other
):
72 return Operator("/", [self
, other
])
73 def __rdiv__(self
, other
):
74 return Operator("/", [other
, self
])
75 def __lshift__(self
, other
):
76 return Operator("<<", [self
, other
])
77 def __rlshift__(self
, other
):
78 return Operator("<<", [other
, self
])
79 def __rshift__(self
, other
):
80 return Operator(">>", [self
, other
])
81 def __rrshift__(self
, other
):
82 return Operator(">>", [other
, self
])
83 def __and__(self
, other
):
84 return Operator("&", [self
, other
])
85 def __rand__(self
, other
):
86 return Operator("&", [other
, self
])
87 def __xor__(self
, other
):
88 return Operator("^", [self
, other
])
89 def __rxor__(self
, other
):
90 return Operator("^", [other
, self
])
91 def __or__(self
, other
):
92 return Operator("|", [self
, other
])
93 def __ror__(self
, other
):
94 return Operator("|", [other
, self
])
96 def __eq__(self
, other
):
97 return Operator("==", [self
, other
])
98 def __ne__(self
, other
):
99 return Operator("!=", [self
, other
])
100 def __lt__(self
, other
):
101 return Operator("<", [self
, other
])
102 def __le__(self
, other
):
103 return Operator("<=", [self
, other
])
104 def __gt__(self
, other
):
105 return Operator(">", [self
, other
])
106 def __ge__(self
, other
):
107 return Operator(">=", [self
, other
])
110 return self
.shape()[0]
112 def __getitem__(self
, key
):
114 if isinstance(key
, int):
115 if key
not in range(-n
, n
):
116 raise IndexError("Cannot index {} bits into {}-bit value".format(key
, n
))
119 return Slice(self
, key
, key
+ 1)
120 elif isinstance(key
, slice):
121 start
, stop
, step
= key
.indices(n
)
123 return Cat(self
[i
] for i
in range(start
, stop
, step
))
124 return Slice(self
, start
, stop
)
126 raise TypeError("Cannot index value with {}".format(repr(key
)))
129 """Conversion to boolean.
134 Output ``Value``. If any bits are set, returns ``1``, else ``0``.
136 return Operator("b", [self
])
138 def implies(premise
, conclusion
):
144 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
146 return ~premise | conclusion
148 def part(self
, offset
, width
):
149 """Indexed part-select.
151 Selects a constant width but variable offset part of a ``Value``.
156 start point of the selected bits
158 number of selected bits
163 Selected part of the ``Value``
165 return Part(self
, offset
, width
)
173 Value to be assigned.
178 Assignment statement that can be used in combinatorial or synchronous context.
180 return Assign(self
, value
)
184 """Bit length and signedness of a value.
189 Number of bits required to store `v` or available in `v`, followed by
190 whether `v` has a sign bit (included in the bit count).
194 >>> Value.shape(Signal(8))
196 >>> Value.shape(C(0xaa))
201 def _lhs_signals(self
):
202 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
205 def _rhs_signals(self
):
209 raise TypeError("Value {!r} cannot be evaluated as constant".format(self
))
216 """A constant, literal integer value.
221 shape : int or tuple or None
222 Either an integer `bits` or a tuple `(bits, signed)`
223 specifying the number of bits in this `Const` and whether it is
224 signed (can represent negative values). `shape` defaults
225 to the minimum width and signedness of `value`.
235 def normalize(value
, shape
):
236 nbits
, signed
= shape
237 mask
= (1 << nbits
) - 1
239 if signed
and value
>> (nbits
- 1):
243 def __init__(self
, value
, shape
=None):
244 self
.value
= int(value
)
246 shape
= bits_for(self
.value
), self
.value
< 0
247 if isinstance(shape
, int):
248 shape
= shape
, self
.value
< 0
249 self
.nbits
, self
.signed
= shape
250 if not isinstance(self
.nbits
, int) or self
.nbits
< 0:
251 raise TypeError("Width must be a non-negative integer, not '{!r}'"
253 self
.value
= self
.normalize(self
.value
, shape
)
256 return self
.nbits
, self
.signed
258 def _rhs_signals(self
):
265 return "(const {}'{}d{})".format(self
.nbits
, "s" if self
.signed
else "", self
.value
)
268 C
= Const
# shorthand
271 class AnyValue(Value
, DUID
):
272 def __init__(self
, shape
):
273 super().__init
__(src_loc_at
=0)
274 if isinstance(shape
, int):
276 self
.nbits
, self
.signed
= shape
277 if not isinstance(self
.nbits
, int) or self
.nbits
< 0:
278 raise TypeError("Width must be a non-negative integer, not '{!r}'"
282 return self
.nbits
, self
.signed
284 def _rhs_signals(self
):
289 class AnyConst(AnyValue
):
291 return "(anyconst {}'{})".format(self
.nbits
, "s" if self
.signed
else "")
295 class AnySeq(AnyValue
):
297 return "(anyseq {}'{})".format(self
.nbits
, "s" if self
.signed
else "")
301 class Operator(Value
):
302 def __init__(self
, op
, operands
, src_loc_at
=0):
303 super().__init
__(src_loc_at
=1 + src_loc_at
)
305 self
.operands
= [Value
.wrap(o
) for o
in operands
]
308 def _bitwise_binary_shape(a_shape
, b_shape
):
309 a_bits
, a_sign
= a_shape
310 b_bits
, b_sign
= b_shape
311 if not a_sign
and not b_sign
:
312 # both operands unsigned
313 return max(a_bits
, b_bits
), False
314 elif a_sign
and b_sign
:
315 # both operands signed
316 return max(a_bits
, b_bits
), True
317 elif not a_sign
and b_sign
:
318 # first operand unsigned (add sign bit), second operand signed
319 return max(a_bits
+ 1, b_bits
), True
321 # first signed, second operand unsigned (add sign bit)
322 return max(a_bits
, b_bits
+ 1), True
325 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
326 if len(op_shapes
) == 1:
327 (a_bits
, a_sign
), = op_shapes
328 if self
.op
in ("+", "~"):
329 return a_bits
, a_sign
332 return a_bits
+ 1, True
334 return a_bits
, a_sign
337 elif len(op_shapes
) == 2:
338 (a_bits
, a_sign
), (b_bits
, b_sign
) = op_shapes
339 if self
.op
== "+" or self
.op
== "-":
340 bits
, sign
= self
._bitwise
_binary
_shape
(*op_shapes
)
341 return bits
+ 1, sign
343 return a_bits
+ b_bits
, a_sign
or b_sign
345 return a_bits
, a_sign
346 if self
.op
in ("<", "<=", "==", "!=", ">", ">=", "b"):
348 if self
.op
in ("&", "^", "|"):
349 return self
._bitwise
_binary
_shape
(*op_shapes
)
352 extra
= 2 ** (b_bits
- 1) - 1
354 extra
= 2 ** (b_bits
) - 1
355 return a_bits
+ extra
, a_sign
358 extra
= 2 ** (b_bits
- 1)
361 return a_bits
+ extra
, a_sign
362 elif len(op_shapes
) == 3:
364 s_shape
, a_shape
, b_shape
= op_shapes
365 return self
._bitwise
_binary
_shape
(a_shape
, b_shape
)
366 raise NotImplementedError("Operator {}/{} not implemented"
367 .format(self
.op
, len(op_shapes
))) # :nocov:
369 def _rhs_signals(self
):
370 return union(op
._rhs
_signals
() for op
in self
.operands
)
373 return "({} {})".format(self
.op
, " ".join(map(repr, self
.operands
)))
376 def Mux(sel
, val1
, val0
):
377 """Choose between two values.
390 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
392 return Operator("m", [sel
, val1
, val0
], src_loc_at
=1)
397 def __init__(self
, value
, start
, end
):
398 if not isinstance(start
, int):
399 raise TypeError("Slice start must be an integer, not '{!r}'".format(start
))
400 if not isinstance(end
, int):
401 raise TypeError("Slice end must be an integer, not '{!r}'".format(end
))
404 if start
not in range(-(n
+1), n
+1):
405 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
408 if end
not in range(-(n
+1), n
+1):
409 raise IndexError("Cannot end slice {} bits into {}-bit value".format(end
, n
))
413 raise IndexError("Slice start {} must be less than slice end {}".format(start
, end
))
416 self
.value
= Value
.wrap(value
)
421 return self
.end
- self
.start
, False
423 def _lhs_signals(self
):
424 return self
.value
._lhs
_signals
()
426 def _rhs_signals(self
):
427 return self
.value
._rhs
_signals
()
430 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.end
)
435 def __init__(self
, value
, offset
, width
):
436 if not isinstance(width
, int) or width
< 0:
437 raise TypeError("Part width must be a non-negative integer, not '{!r}'".format(width
))
441 self
.offset
= Value
.wrap(offset
)
445 return self
.width
, False
447 def _lhs_signals(self
):
448 return self
.value
._lhs
_signals
()
450 def _rhs_signals(self
):
451 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
454 return "(part {} {} {})".format(repr(self
.value
), repr(self
.offset
), self
.width
)
459 """Concatenate values.
461 Form a compound ``Value`` from several smaller ones by concatenation.
462 The first argument occupies the lower bits of the result.
463 The return value can be used on either side of an assignment, that
464 is, the concatenated value can be used as an argument on the RHS or
465 as a target on the LHS. If it is used on the LHS, it must solely
466 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
467 meeting these properties. The bit length of the return value is the sum of
468 the bit lengths of the arguments::
470 len(Cat(args)) == sum(len(arg) for arg in args)
474 *args : Values or iterables of Values, inout
475 ``Value`` s to be concatenated.
480 Resulting ``Value`` obtained by concatentation.
482 def __init__(self
, *args
):
484 self
.parts
= [Value
.wrap(v
) for v
in flatten(args
)]
487 return sum(len(part
) for part
in self
.parts
), False
489 def _lhs_signals(self
):
490 return union((part
._lhs
_signals
() for part
in self
.parts
), start
=ValueSet())
492 def _rhs_signals(self
):
493 return union((part
._rhs
_signals
() for part
in self
.parts
), start
=ValueSet())
497 for part
in reversed(self
.parts
):
499 value |
= part
._as
_const
()
503 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
510 An input value is replicated (repeated) several times
511 to be used on the RHS of assignments::
513 len(Repl(s, n)) == len(s) * n
518 Input value to be replicated.
520 Number of replications.
527 def __init__(self
, value
, count
):
528 if not isinstance(count
, int) or count
< 0:
529 raise TypeError("Replication count must be a non-negative integer, not '{!r}'"
533 self
.value
= Value
.wrap(value
)
537 return len(self
.value
) * self
.count
, False
539 def _rhs_signals(self
):
540 return self
.value
._rhs
_signals
()
543 return "(repl {!r} {})".format(self
.value
, self
.count
)
547 class Signal(Value
, DUID
):
548 """A varying integer value.
552 shape : int or tuple or None
553 Either an integer ``bits`` or a tuple ``(bits, signed)`` specifying the number of bits
554 in this ``Signal`` and whether it is signed (can represent negative values).
555 ``shape`` defaults to 1-bit and non-signed.
557 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
558 name this ``Signal`` is assigned to. Name collisions are automatically resolved by
559 prepending names of objects that contain this ``Signal`` and by appending integer
562 Reset (synchronous) or default (combinatorial) value.
563 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
564 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
565 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
566 assumes its ``reset`` value. Defaults to 0.
568 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
569 The ``reset`` value is only used as a combinatorial default or as the initial value.
570 Defaults to ``False``.
573 If ``shape`` is ``None``, the signal bit width and signedness are
574 determined by the integer range given by ``min`` (inclusive,
575 defaults to 0) and ``max`` (exclusive, defaults to 2).
577 Dictionary of synthesis attributes.
579 A function converting integer signal values to human-readable strings (e.g. FSM state
592 def __init__(self
, shape
=None, name
=None, reset
=0, reset_less
=False, min=None, max=None,
593 attrs
=None, decoder
=None, src_loc_at
=0):
594 super().__init
__(src_loc_at
=src_loc_at
)
596 if name
is not None and not isinstance(name
, str):
597 raise TypeError("Name must be a string, not '{!r}'".format(name
))
598 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$signal")
605 max -= 1 # make both bounds inclusive
607 raise ValueError("Lower bound {} should be less or equal to higher bound {}"
608 .format(min, max + 1))
609 self
.signed
= min < 0 or max < 0
613 self
.nbits
= builtins
.max(bits_for(min, self
.signed
),
614 bits_for(max, self
.signed
))
617 if not (min is None and max is None):
618 raise ValueError("Only one of bits/signedness or bounds may be specified")
619 if isinstance(shape
, int):
620 self
.nbits
, self
.signed
= shape
, False
622 self
.nbits
, self
.signed
= shape
624 if not isinstance(self
.nbits
, int) or self
.nbits
< 0:
625 raise TypeError("Width must be a non-negative integer, not '{!r}'".format(self
.nbits
))
626 self
.reset
= int(reset
)
627 self
.reset_less
= bool(reset_less
)
629 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
630 self
.decoder
= decoder
633 def like(cls
, other
, name
=None, name_suffix
=None, src_loc_at
=0, **kwargs
):
634 """Create Signal based on another.
639 Object to base this Signal on.
643 elif name_suffix
is not None:
644 new_name
= other
.name
+ str(name_suffix
)
646 new_name
= tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$like")
647 kw
= dict(shape
=cls
.wrap(other
).shape(), name
=new_name
)
648 if isinstance(other
, cls
):
649 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
650 attrs
=other
.attrs
, decoder
=other
.decoder
)
652 return cls(**kw
, src_loc_at
=1 + src_loc_at
)
655 return self
.nbits
, self
.signed
657 def _lhs_signals(self
):
658 return ValueSet((self
,))
660 def _rhs_signals(self
):
661 return ValueSet((self
,))
664 return "(sig {})".format(self
.name
)
668 class ClockSignal(Value
):
669 """Clock signal for a clock domain.
671 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
672 All of these signals ultimately refer to the same signal, but they can be manipulated
673 independently of the clock domain, even before the clock domain is created.
678 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
680 def __init__(self
, domain
="sync"):
682 if not isinstance(domain
, str):
683 raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain
))
689 def _lhs_signals(self
):
690 return ValueSet((self
,))
692 def _rhs_signals(self
):
693 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
696 return "(clk {})".format(self
.domain
)
700 class ResetSignal(Value
):
701 """Reset signal for a clock domain.
703 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
704 All of these signals ultimately refer to the same signal, but they can be manipulated
705 independently of the clock domain, even before the clock domain is created.
710 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
711 allow_reset_less : bool
712 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
714 def __init__(self
, domain
="sync", allow_reset_less
=False):
716 if not isinstance(domain
, str):
717 raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain
))
719 self
.allow_reset_less
= allow_reset_less
724 def _lhs_signals(self
):
725 return ValueSet((self
,))
727 def _rhs_signals(self
):
728 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
731 return "(rst {})".format(self
.domain
)
734 class Array(MutableSequence
):
735 """Addressable multiplexer.
737 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
740 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
741 assignments, provided that all elements of the array are values. The array proxy also supports
742 attribute access and further indexing, each returning another array proxy; this means that
743 the results of indexing into arrays, arrays of records, and arrays of arrays can all
744 be used as first-class values.
746 It is an error to change an array or any of its elements after an array proxy was created.
747 Changing the array directly will raise an exception. However, it is not possible to detect
748 the elements being modified; if an element's attribute or element is modified after the proxy
749 for it has been created, the proxy will refer to stale data.
756 gpios = Array(Signal() for _ in range(10))
758 m.d.sync += gpios[bus.adr].eq(bus.dat_w)
760 m.d.sync += bus.dat_r.eq(gpios[bus.adr])
762 Multidimensional array::
764 mult = Array(Array(x * y for y in range(10)) for x in range(10))
768 m.d.comb += r.eq(mult[a][b])
776 buses = Array(Record(layout) for busno in range(4))
777 master = Record(layout)
779 buses[sel].re.eq(master.re),
780 master.dat_r.eq(buses[sel].dat_r),
783 def __init__(self
, iterable
=()):
784 self
._inner
= list(iterable
)
785 self
._proxy
_at
= None
788 def __getitem__(self
, index
):
789 if isinstance(index
, Value
):
791 self
._proxy
_at
= tracer
.get_src_loc()
792 self
._mutable
= False
793 return ArrayProxy(self
, index
)
795 return self
._inner
[index
]
798 return len(self
._inner
)
800 def _check_mutability(self
):
801 if not self
._mutable
:
802 raise ValueError("Array can no longer be mutated after it was indexed with a value "
803 "at {}:{}".format(*self
._proxy
_at
))
805 def __setitem__(self
, index
, value
):
806 self
._check
_mutability
()
807 self
._inner
[index
] = value
809 def __delitem__(self
, index
):
810 self
._check
_mutability
()
811 del self
._inner
[index
]
813 def insert(self
, index
, value
):
814 self
._check
_mutability
()
815 self
._inner
.insert(index
, value
)
818 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
819 ", ".join(map(repr, self
._inner
)))
823 class ArrayProxy(Value
):
824 def __init__(self
, elems
, index
):
825 super().__init
__(src_loc_at
=1)
827 self
.index
= Value
.wrap(index
)
829 def __getattr__(self
, attr
):
830 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
832 def __getitem__(self
, index
):
833 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
835 def _iter_as_values(self
):
836 return (Value
.wrap(elem
) for elem
in self
.elems
)
839 bits
, sign
= 0, False
840 for elem_bits
, elem_sign
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
841 bits
= max(bits
, elem_bits
+ elem_sign
)
842 sign
= max(sign
, elem_sign
)
845 def _lhs_signals(self
):
846 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()), start
=ValueSet())
849 def _rhs_signals(self
):
850 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()), start
=ValueSet())
851 return self
.index
._rhs
_signals
() | signals
854 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
857 class UserValue(Value
):
858 """Value with custom lowering.
860 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
861 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
862 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
865 Note that the ``lower`` method will only be called once; this is necessary to ensure that
866 nMigen's view of representation of all values stays internally consistent. If the class
867 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
868 it is not mutated in a way that changes its representation.
870 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
871 or indirectly, will cause it to be lowered, provided as an illustrative reference:
872 * Querying the shape using ``.shape()`` or ``len()``;
873 * Creating a similarly shaped signal using ``Signal.like``;
874 * Indexing or iterating through individual bits;
875 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
877 def __init__(self
, src_loc_at
=1):
878 super().__init
__(src_loc_at
=1 + src_loc_at
)
879 self
.__lowered
= None
883 """Conversion to a concrete representation."""
886 def _lazy_lower(self
):
887 if self
.__lowered
is None:
888 self
.__lowered
= Value
.wrap(self
.lower())
889 return self
.__lowered
892 return self
._lazy
_lower
().shape()
894 def _lhs_signals(self
):
895 return self
._lazy
_lower
()._lhs
_signals
()
897 def _rhs_signals(self
):
898 return self
._lazy
_lower
()._rhs
_signals
()
903 """Value from the past.
905 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
906 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
907 to the value of the expression calculated as if each signal had its reset value.
909 def __init__(self
, expr
, clocks
, domain
):
910 super().__init
__(src_loc_at
=1)
911 self
.value
= Value
.wrap(expr
)
912 self
.clocks
= int(clocks
)
914 if not isinstance(self
.value
, (Const
, Signal
, ClockSignal
, ResetSignal
)):
915 raise TypeError("Sampled value may only be a signal or a constant, not {!r}"
918 raise ValueError("Cannot sample a value {} cycles in the future"
919 .format(-self
.clocks
))
922 return self
.value
.shape()
924 def _rhs_signals(self
):
925 return ValueSet((self
,))
928 return "(sample {!r} @ {}[{}])".format(
929 self
.value
, "<default>" if self
.domain
is None else self
.domain
, self
.clocks
)
932 def Past(expr
, clocks
=1, domain
=None):
933 return Sample(expr
, clocks
, domain
)
936 def Stable(expr
, clocks
=0, domain
=None):
937 return Sample(expr
, clocks
+ 1, domain
) == Sample(expr
, clocks
, domain
)
940 def Rose(expr
, clocks
=0, domain
=None):
941 return ~
Sample(expr
, clocks
+ 1, domain
) & Sample(expr
, clocks
, domain
)
944 def Fell(expr
, clocks
=0, domain
=None):
945 return Sample(expr
, clocks
+ 1, domain
) & ~
Sample(expr
, clocks
, domain
)
948 class _StatementList(list):
950 return "({})".format(" ".join(map(repr, self
)))
956 if isinstance(obj
, Iterable
):
957 return _StatementList(sum((Statement
.wrap(e
) for e
in obj
), []))
959 if isinstance(obj
, Statement
):
960 return _StatementList([obj
])
962 raise TypeError("Object '{!r}' is not an nMigen statement".format(obj
))
966 class Assign(Statement
):
967 def __init__(self
, lhs
, rhs
):
968 self
.lhs
= Value
.wrap(lhs
)
969 self
.rhs
= Value
.wrap(rhs
)
971 def _lhs_signals(self
):
972 return self
.lhs
._lhs
_signals
()
974 def _rhs_signals(self
):
975 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
978 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
981 class Property(Statement
):
982 def __init__(self
, test
, _check
=None, _en
=None):
983 self
.src_loc
= tracer
.get_src_loc()
985 self
.test
= Value
.wrap(test
)
988 if self
._check
is None:
989 self
._check
= Signal(reset_less
=True, name
="${}$check".format(self
._kind
))
990 self
._check
.src_loc
= self
.src_loc
994 self
._en
= Signal(reset_less
=True, name
="${}$en".format(self
._kind
))
995 self
._en
.src_loc
= self
.src_loc
997 def _lhs_signals(self
):
998 return ValueSet((self
._en
, self
._check
))
1000 def _rhs_signals(self
):
1001 return self
.test
._rhs
_signals
()
1004 return "({} {!r})".format(self
._kind
, self
.test
)
1008 class Assert(Property
):
1013 class Assume(Property
):
1018 class Switch(Statement
):
1019 def __init__(self
, test
, cases
):
1020 self
.test
= Value
.wrap(test
)
1021 self
.cases
= OrderedDict()
1022 for keys
, stmts
in cases
.items():
1023 # Map: None -> (); key -> (key,); (key...) -> (key...)
1026 if not isinstance(keys
, tuple):
1028 # Map: 2 -> "0010"; "0010" -> "0010"
1031 if isinstance(key
, (bool, int)):
1032 key
= "{:0{}b}".format(key
, len(self
.test
))
1033 elif isinstance(key
, str):
1036 raise TypeError("Object '{!r}' cannot be used as a switch key"
1038 assert len(key
) == len(self
.test
)
1039 new_keys
= (*new_keys
, key
)
1040 if not isinstance(stmts
, Iterable
):
1042 self
.cases
[new_keys
] = Statement
.wrap(stmts
)
1044 def _lhs_signals(self
):
1045 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1049 def _rhs_signals(self
):
1050 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1052 return self
.test
._rhs
_signals
() | signals
1055 def case_repr(keys
, stmts
):
1056 stmts_repr
= " ".join(map(repr, stmts
))
1058 return "(default {})".format(stmts_repr
)
1059 elif len(keys
) == 1:
1060 return "(case {} {})".format(keys
[0], stmts_repr
)
1062 return "(case ({}) {})".format(" ".join(keys
), stmts_repr
)
1063 case_reprs
= [case_repr(keys
, stmts
) for keys
, stmts
in self
.cases
.items()]
1064 return "(switch {!r} {})".format(self
.test
, " ".join(case_reprs
))
1068 class Delay(Statement
):
1069 def __init__(self
, interval
=None):
1070 self
.interval
= None if interval
is None else float(interval
)
1072 def _rhs_signals(self
):
1076 if self
.interval
is None:
1079 return "(delay {:.3}us)".format(self
.interval
* 1e6
)
1083 class Tick(Statement
):
1084 def __init__(self
, domain
="sync"):
1085 self
.domain
= str(domain
)
1087 def _rhs_signals(self
):
1091 return "(tick {})".format(self
.domain
)
1095 class Passive(Statement
):
1096 def _rhs_signals(self
):
1103 class _MappedKeyCollection(metaclass
=ABCMeta
):
1105 def _map_key(self
, key
):
1109 def _unmap_key(self
, key
):
1113 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
1114 def __init__(self
, pairs
=()):
1115 self
._storage
= OrderedDict()
1116 for key
, value
in pairs
:
1119 def __getitem__(self
, key
):
1120 key
= None if key
is None else self
._map
_key
(key
)
1121 return self
._storage
[key
]
1123 def __setitem__(self
, key
, value
):
1124 key
= None if key
is None else self
._map
_key
(key
)
1125 self
._storage
[key
] = value
1127 def __delitem__(self
, key
):
1128 key
= None if key
is None else self
._map
_key
(key
)
1129 del self
._storage
[key
]
1132 for key
in self
._storage
:
1136 yield self
._unmap
_key
(key
)
1138 def __eq__(self
, other
):
1139 if not isinstance(other
, type(self
)):
1141 if len(self
) != len(other
):
1143 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
1146 if self
._storage
[ak
] != other
._storage
[bk
]:
1151 return len(self
._storage
)
1154 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
1155 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
1159 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
1160 def __init__(self
, elements
=()):
1161 self
._storage
= OrderedDict()
1162 for elem
in elements
:
1165 def add(self
, value
):
1166 self
._storage
[self
._map
_key
(value
)] = None
1168 def update(self
, values
):
1169 for value
in values
:
1172 def discard(self
, value
):
1174 del self
._storage
[self
._map
_key
(value
)]
1176 def __contains__(self
, value
):
1177 return self
._map
_key
(value
) in self
._storage
1180 for key
in [k
for k
in self
._storage
]:
1181 yield self
._unmap
_key
(key
)
1184 return len(self
._storage
)
1187 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
1188 ", ".join(repr(x
) for x
in self
))
1192 def __init__(self
, value
):
1193 self
.value
= Value
.wrap(value
)
1196 if isinstance(self
.value
, Const
):
1197 return hash(self
.value
.value
)
1198 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1199 return hash(self
.value
.duid
)
1200 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1201 return hash(self
.value
.domain
)
1202 elif isinstance(self
.value
, Operator
):
1203 return hash((self
.value
.op
, tuple(ValueKey(o
) for o
in self
.value
.operands
)))
1204 elif isinstance(self
.value
, Slice
):
1205 return hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.end
))
1206 elif isinstance(self
.value
, Part
):
1207 return hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
1209 elif isinstance(self
.value
, Cat
):
1210 return hash(tuple(ValueKey(o
) for o
in self
.value
.parts
))
1211 elif isinstance(self
.value
, ArrayProxy
):
1212 return hash((ValueKey(self
.value
.index
),
1213 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
1214 elif isinstance(self
.value
, Sample
):
1215 return hash((ValueKey(self
.value
.value
), self
.value
.clocks
, self
.value
.domain
))
1217 raise TypeError("Object '{!r}' cannot be used as a key in value collections"
1218 .format(self
.value
))
1220 def __eq__(self
, other
):
1221 if type(other
) is not ValueKey
:
1223 if type(self
.value
) is not type(other
.value
):
1226 if isinstance(self
.value
, Const
):
1227 return self
.value
.value
== other
.value
.value
1228 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1229 return self
.value
is other
.value
1230 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1231 return self
.value
.domain
== other
.value
.domain
1232 elif isinstance(self
.value
, Operator
):
1233 return (self
.value
.op
== other
.value
.op
and
1234 len(self
.value
.operands
) == len(other
.value
.operands
) and
1235 all(ValueKey(a
) == ValueKey(b
)
1236 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1237 elif isinstance(self
.value
, Slice
):
1238 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1239 self
.value
.start
== other
.value
.start
and
1240 self
.value
.end
== other
.value
.end
)
1241 elif isinstance(self
.value
, Part
):
1242 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1243 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1244 self
.value
.width
== other
.value
.width
)
1245 elif isinstance(self
.value
, Cat
):
1246 return all(ValueKey(a
) == ValueKey(b
)
1247 for a
, b
in zip(self
.value
.parts
, other
.value
.parts
))
1248 elif isinstance(self
.value
, ArrayProxy
):
1249 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1250 len(self
.value
.elems
) == len(other
.value
.elems
) and
1251 all(ValueKey(a
) == ValueKey(b
)
1252 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1253 other
.value
._iter
_as
_values
())))
1254 elif isinstance(self
.value
, Sample
):
1255 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1256 self
.value
.clocks
== other
.value
.clocks
and
1257 self
.value
.domain
== self
.value
.domain
)
1259 raise TypeError("Object '{!r}' cannot be used as a key in value collections"
1260 .format(self
.value
))
1262 def __lt__(self
, other
):
1263 if not isinstance(other
, ValueKey
):
1265 if type(self
.value
) != type(other
.value
):
1268 if isinstance(self
.value
, Const
):
1269 return self
.value
< other
.value
1270 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1271 return self
.value
.duid
< other
.value
.duid
1272 elif isinstance(self
.value
, Slice
):
1273 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1274 self
.value
.start
< other
.value
.start
and
1275 self
.value
.end
< other
.value
.end
)
1277 raise TypeError("Object '{!r}' cannot be used as a key in value collections")
1280 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1283 class ValueDict(_MappedKeyDict
):
1285 _unmap_key
= lambda self
, key
: key
.value
1288 class ValueSet(_MappedKeySet
):
1290 _unmap_key
= lambda self
, key
: key
.value
1294 def __init__(self
, signal
):
1295 if type(signal
) is Signal
:
1296 self
._intern
= (0, signal
.duid
)
1297 elif type(signal
) is ClockSignal
:
1298 self
._intern
= (1, signal
.domain
)
1299 elif type(signal
) is ResetSignal
:
1300 self
._intern
= (2, signal
.domain
)
1302 raise TypeError("Object '{!r}' is not an nMigen signal".format(signal
))
1303 self
.signal
= signal
1306 return hash(self
._intern
)
1308 def __eq__(self
, other
):
1309 if type(other
) is not SignalKey
:
1311 return self
._intern
== other
._intern
1313 def __lt__(self
, other
):
1314 if type(other
) is not SignalKey
:
1315 raise TypeError("Object '{!r}' cannot be compared to a SignalKey".format(signal
))
1316 return self
._intern
< other
._intern
1319 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1322 class SignalDict(_MappedKeyDict
):
1323 _map_key
= SignalKey
1324 _unmap_key
= lambda self
, key
: key
.signal
1327 class SignalSet(_MappedKeySet
):
1328 _map_key
= SignalKey
1329 _unmap_key
= lambda self
, key
: key
.signal