1 from abc
import ABCMeta
, abstractmethod
5 from collections
import OrderedDict
6 from collections
.abc
import Iterable
, MutableMapping
, MutableSet
, MutableSequence
10 from .._utils
import *
11 from .._unused
import *
15 "Shape", "signed", "unsigned",
16 "Value", "Const", "C", "AnyConst", "AnySeq", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
17 "Array", "ArrayProxy",
18 "Signal", "ClockSignal", "ResetSignal",
20 "Sample", "Past", "Stable", "Rose", "Fell", "Initial",
21 "Statement", "Switch",
22 "Property", "Assign", "Assert", "Assume", "Cover",
23 "ValueKey", "ValueDict", "ValueSet", "SignalKey", "SignalDict", "SignalSet",
28 """Deterministic Unique IDentifier."""
31 self
.duid
= DUID
.__next
_uid
35 class Shape(typing
.NamedTuple
):
36 """Bit width and signedness of a value.
38 A ``Shape`` can be constructed using:
39 * explicit bit width and signedness;
40 * aliases :func:`signed` and :func:`unsigned`;
41 * casting from a variety of objects.
43 A ``Shape`` can be cast from:
44 * an integer, where the integer specifies the bit width;
45 * a range, where the result is wide enough to represent any element of the range, and is
46 signed if any element of the range is signed;
47 * an :class:`Enum` with all integer members or :class:`IntEnum`, where the result is wide
48 enough to represent any member of the enumeration, and is signed if any member of
49 the enumeration is signed.
54 The number of bits in the representation, including the sign bit (if any).
56 If ``False``, the value is unsigned. If ``True``, the value is signed two's complement.
62 def cast(obj
, *, src_loc_at
=0):
63 if isinstance(obj
, Shape
):
65 if isinstance(obj
, int):
67 if isinstance(obj
, tuple):
69 warnings
.warn("instead of `{tuple}`, use `{constructor}({width})`"
70 .format(constructor
="signed" if signed
else "unsigned", width
=width
,
72 DeprecationWarning, stacklevel
=2 + src_loc_at
)
73 return Shape(width
, signed
)
74 if isinstance(obj
, range):
76 return Shape(0, obj
.start
< 0)
77 signed
= obj
.start
< 0 or (obj
.stop
- obj
.step
) < 0
78 width
= max(bits_for(obj
.start
, signed
),
79 bits_for(obj
.stop
- obj
.step
, signed
))
80 return Shape(width
, signed
)
81 if isinstance(obj
, type) and issubclass(obj
, Enum
):
82 min_value
= min(member
.value
for member
in obj
)
83 max_value
= max(member
.value
for member
in obj
)
84 if not isinstance(min_value
, int) or not isinstance(max_value
, int):
85 raise TypeError("Only enumerations with integer values can be used "
87 signed
= min_value
< 0 or max_value
< 0
88 width
= max(bits_for(min_value
, signed
), bits_for(max_value
, signed
))
89 return Shape(width
, signed
)
90 raise TypeError("Object {!r} cannot be used as value shape".format(obj
))
93 # TODO: use dataclasses instead of this hack
94 def _Shape___init__(self
, width
=1, signed
=False):
95 if not isinstance(width
, int) or width
< 0:
96 raise TypeError("Width must be a non-negative integer, not {!r}"
98 Shape
.__init
__ = _Shape___init__
102 """Shorthand for ``Shape(width, signed=False)``."""
103 return Shape(width
, signed
=False)
107 """Shorthand for ``Shape(width, signed=True)``."""
108 return Shape(width
, signed
=True)
111 class Value(metaclass
=ABCMeta
):
114 """Converts ``obj`` to an nMigen value.
116 Booleans and integers are wrapped into a :class:`Const`. Enumerations whose members are
117 all integers are converted to a :class:`Const` with a shape that fits every member.
119 if isinstance(obj
, Value
):
121 if isinstance(obj
, int):
123 if isinstance(obj
, Enum
):
124 return Const(obj
.value
, Shape
.cast(type(obj
)))
125 raise TypeError("Object {!r} cannot be converted to an nMigen value".format(obj
))
127 def __init__(self
, *, src_loc_at
=0):
129 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
132 raise TypeError("Attempted to convert nMigen value to boolean")
134 def __invert__(self
):
135 return Operator("~", [self
])
137 return Operator("-", [self
])
139 def __add__(self
, other
):
140 return Operator("+", [self
, other
])
141 def __radd__(self
, other
):
142 return Operator("+", [other
, self
])
143 def __sub__(self
, other
):
144 return Operator("-", [self
, other
])
145 def __rsub__(self
, other
):
146 return Operator("-", [other
, self
])
148 def __mul__(self
, other
):
149 return Operator("*", [self
, other
])
150 def __rmul__(self
, other
):
151 return Operator("*", [other
, self
])
153 def __check_divisor(self
):
154 width
, signed
= self
.shape()
156 # Python's division semantics and Verilog's division semantics differ for negative
157 # divisors (Python uses div/mod, Verilog uses quo/rem); for now, avoid the issue
158 # completely by prohibiting such division operations.
159 raise NotImplementedError("Division by a signed value is not supported")
160 def __mod__(self
, other
):
161 other
= Value
.cast(other
)
162 other
.__check
_divisor
()
163 return Operator("%", [self
, other
])
164 def __rmod__(self
, other
):
165 self
.__check
_divisor
()
166 return Operator("%", [other
, self
])
167 def __floordiv__(self
, other
):
168 other
= Value
.cast(other
)
169 other
.__check
_divisor
()
170 return Operator("//", [self
, other
])
171 def __rfloordiv__(self
, other
):
172 self
.__check
_divisor
()
173 return Operator("//", [other
, self
])
175 def __check_shamt(self
):
176 width
, signed
= self
.shape()
178 # Neither Python nor HDLs implement shifts by negative values; prohibit any shifts
179 # by a signed value to make sure the shift amount can always be interpreted as
181 raise NotImplementedError("Shift by a signed value is not supported")
182 def __lshift__(self
, other
):
183 other
= Value
.cast(other
)
184 other
.__check
_shamt
()
185 return Operator("<<", [self
, other
])
186 def __rlshift__(self
, other
):
188 return Operator("<<", [other
, self
])
189 def __rshift__(self
, other
):
190 other
= Value
.cast(other
)
191 other
.__check
_shamt
()
192 return Operator(">>", [self
, other
])
193 def __rrshift__(self
, other
):
195 return Operator(">>", [other
, self
])
197 def __and__(self
, other
):
198 return Operator("&", [self
, other
])
199 def __rand__(self
, other
):
200 return Operator("&", [other
, self
])
201 def __xor__(self
, other
):
202 return Operator("^", [self
, other
])
203 def __rxor__(self
, other
):
204 return Operator("^", [other
, self
])
205 def __or__(self
, other
):
206 return Operator("|", [self
, other
])
207 def __ror__(self
, other
):
208 return Operator("|", [other
, self
])
210 def __eq__(self
, other
):
211 return Operator("==", [self
, other
])
212 def __ne__(self
, other
):
213 return Operator("!=", [self
, other
])
214 def __lt__(self
, other
):
215 return Operator("<", [self
, other
])
216 def __le__(self
, other
):
217 return Operator("<=", [self
, other
])
218 def __gt__(self
, other
):
219 return Operator(">", [self
, other
])
220 def __ge__(self
, other
):
221 return Operator(">=", [self
, other
])
224 return self
.shape().width
226 def __getitem__(self
, key
):
228 if isinstance(key
, int):
229 if key
not in range(-n
, n
):
230 raise IndexError("Cannot index {} bits into {}-bit value".format(key
, n
))
233 return Slice(self
, key
, key
+ 1)
234 elif isinstance(key
, slice):
235 start
, stop
, step
= key
.indices(n
)
237 return Cat(self
[i
] for i
in range(start
, stop
, step
))
238 return Slice(self
, start
, stop
)
240 raise TypeError("Cannot index value with {}".format(repr(key
)))
243 """Conversion to boolean.
248 ``1`` if any bits are set, ``0`` otherwise.
250 return Operator("b", [self
])
253 """Check if any bits are ``1``.
258 ``1`` if any bits are set, ``0`` otherwise.
260 return Operator("r|", [self
])
263 """Check if all bits are ``1``.
268 ``1`` if all bits are set, ``0`` otherwise.
270 return Operator("r&", [self
])
273 """Compute pairwise exclusive-or of every bit.
278 ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set.
280 return Operator("r^", [self
])
282 def implies(premise
, conclusion
):
288 ``0`` if ``premise`` is true and ``conclusion`` is not, ``1`` otherwise.
290 return ~premise | conclusion
292 def bit_select(self
, offset
, width
):
293 """Part-select with bit granularity.
295 Selects a constant width but variable offset part of a ``Value``, such that successive
296 parts overlap by all but 1 bit.
301 Index of first selected bit.
303 Number of selected bits.
308 Selected part of the ``Value``
310 offset
= Value
.cast(offset
)
311 if type(offset
) is Const
and isinstance(width
, int):
312 return self
[offset
.value
:offset
.value
+ width
]
313 return Part(self
, offset
, width
, stride
=1, src_loc_at
=1)
315 def word_select(self
, offset
, width
):
316 """Part-select with word granularity.
318 Selects a constant width but variable offset part of a ``Value``, such that successive
319 parts do not overlap.
324 Index of first selected word.
326 Number of selected bits.
331 Selected part of the ``Value``
333 offset
= Value
.cast(offset
)
334 if type(offset
) is Const
and isinstance(width
, int):
335 return self
[offset
.value
* width
:(offset
.value
+ 1) * width
]
336 return Part(self
, offset
, width
, stride
=width
, src_loc_at
=1)
338 def matches(self
, *patterns
):
341 Matches against a set of patterns, which may be integers or bit strings, recognizing
342 the same grammar as ``Case()``.
346 patterns : int or str
347 Patterns to match against.
352 ``1`` if any pattern matches the value, ``0`` otherwise.
355 for pattern
in patterns
:
356 if not isinstance(pattern
, (int, str, Enum
)):
357 raise SyntaxError("Match pattern must be an integer, a string, or an enumeration, "
360 if isinstance(pattern
, str) and any(bit
not in "01- \t" for bit
in pattern
):
361 raise SyntaxError("Match pattern '{}' must consist of 0, 1, and - (don't care) "
362 "bits, and may include whitespace"
364 if (isinstance(pattern
, str) and
365 len("".join(pattern
.split())) != len(self
)):
366 raise SyntaxError("Match pattern '{}' must have the same width as match value "
368 .format(pattern
, len(self
)))
369 if isinstance(pattern
, int) and bits_for(pattern
) > len(self
):
370 warnings
.warn("Match pattern '{:b}' is wider than match value "
371 "(which has width {}); comparison will never be true"
372 .format(pattern
, len(self
)),
373 SyntaxWarning, stacklevel
=3)
375 if isinstance(pattern
, str):
376 pattern
= "".join(pattern
.split()) # remove whitespace
377 mask
= int(pattern
.replace("0", "1").replace("-", "0"), 2)
378 pattern
= int(pattern
.replace("-", "0"), 2)
379 matches
.append((self
& mask
) == pattern
)
380 elif isinstance(pattern
, int):
381 matches
.append(self
== pattern
)
382 elif isinstance(pattern
, Enum
):
383 matches
.append(self
== pattern
.value
)
388 elif len(matches
) == 1:
391 return Cat(*matches
).any()
399 Value to be assigned.
404 Assignment statement that can be used in combinatorial or synchronous context.
406 return Assign(self
, value
, src_loc_at
=1)
410 """Bit width and signedness of a value.
419 >>> Signal(8).shape()
420 Shape(width=8, signed=False)
421 >>> Const(0xaa).shape()
422 Shape(width=8, signed=False)
426 def _lhs_signals(self
):
427 raise TypeError("Value {!r} cannot be used in assignments".format(self
))
430 def _rhs_signals(self
):
434 raise TypeError("Value {!r} cannot be evaluated as constant".format(self
))
441 """A constant, literal integer value.
446 shape : int or tuple or None
447 Either an integer ``width`` or a tuple ``(width, signed)`` specifying the number of bits
448 in this constant and whether it is signed (can represent negative values).
449 ``shape`` defaults to the minimum possible width and signedness of ``value``.
459 def normalize(value
, shape
):
460 width
, signed
= shape
461 mask
= (1 << width
) - 1
463 if signed
and value
>> (width
- 1):
467 def __init__(self
, value
, shape
=None, *, src_loc_at
=0):
468 # We deliberately do not call Value.__init__ here.
469 self
.value
= int(value
)
471 shape
= Shape(bits_for(self
.value
), signed
=self
.value
< 0)
472 elif isinstance(shape
, int):
473 shape
= Shape(shape
, signed
=self
.value
< 0)
475 shape
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
476 self
.width
, self
.signed
= shape
477 self
.value
= self
.normalize(self
.value
, shape
)
480 return Shape(self
.width
, self
.signed
)
482 def _rhs_signals(self
):
489 return "(const {}'{}d{})".format(self
.width
, "s" if self
.signed
else "", self
.value
)
492 C
= Const
# shorthand
495 class AnyValue(Value
, DUID
):
496 def __init__(self
, shape
, *, src_loc_at
=0):
497 super().__init
__(src_loc_at
=src_loc_at
)
498 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
499 if not isinstance(self
.width
, int) or self
.width
< 0:
500 raise TypeError("Width must be a non-negative integer, not {!r}"
504 return Shape(self
.width
, self
.signed
)
506 def _rhs_signals(self
):
511 class AnyConst(AnyValue
):
513 return "(anyconst {}'{})".format(self
.width
, "s" if self
.signed
else "")
517 class AnySeq(AnyValue
):
519 return "(anyseq {}'{})".format(self
.width
, "s" if self
.signed
else "")
523 class Operator(Value
):
524 def __init__(self
, operator
, operands
, *, src_loc_at
=0):
525 super().__init
__(src_loc_at
=1 + src_loc_at
)
526 self
.operator
= operator
527 self
.operands
= [Value
.cast(op
) for op
in operands
]
530 def _bitwise_binary_shape(a_shape
, b_shape
):
531 a_bits
, a_sign
= a_shape
532 b_bits
, b_sign
= b_shape
533 if not a_sign
and not b_sign
:
534 # both operands unsigned
535 return Shape(max(a_bits
, b_bits
), False)
536 elif a_sign
and b_sign
:
537 # both operands signed
538 return Shape(max(a_bits
, b_bits
), True)
539 elif not a_sign
and b_sign
:
540 # first operand unsigned (add sign bit), second operand signed
541 return Shape(max(a_bits
+ 1, b_bits
), True)
543 # first signed, second operand unsigned (add sign bit)
544 return Shape(max(a_bits
, b_bits
+ 1), True)
546 op_shapes
= list(map(lambda x
: x
.shape(), self
.operands
))
547 if len(op_shapes
) == 1:
548 (a_width
, a_signed
), = op_shapes
549 if self
.operator
in ("+", "~"):
550 return Shape(a_width
, a_signed
)
551 if self
.operator
== "-":
552 return Shape(a_width
+ 1, True)
553 if self
.operator
in ("b", "r|", "r&", "r^"):
554 return Shape(1, False)
555 elif len(op_shapes
) == 2:
556 (a_width
, a_signed
), (b_width
, b_signed
) = op_shapes
557 if self
.operator
in ("+", "-"):
558 width
, signed
= _bitwise_binary_shape(*op_shapes
)
559 return Shape(width
+ 1, signed
)
560 if self
.operator
== "*":
561 return Shape(a_width
+ b_width
, a_signed
or b_signed
)
562 if self
.operator
in ("//", "%"):
564 return Shape(a_width
, a_signed
)
565 if self
.operator
in ("<", "<=", "==", "!=", ">", ">="):
566 return Shape(1, False)
567 if self
.operator
in ("&", "^", "|"):
568 return _bitwise_binary_shape(*op_shapes
)
569 if self
.operator
== "<<":
571 extra
= 2 ** (b_width
- 1) - 1
573 extra
= 2 ** (b_width
) - 1
574 return Shape(a_width
+ extra
, a_signed
)
575 if self
.operator
== ">>":
577 extra
= 2 ** (b_width
- 1)
580 return Shape(a_width
+ extra
, a_signed
)
581 elif len(op_shapes
) == 3:
582 if self
.operator
== "m":
583 s_shape
, a_shape
, b_shape
= op_shapes
584 return _bitwise_binary_shape(a_shape
, b_shape
)
585 raise NotImplementedError("Operator {}/{} not implemented"
586 .format(self
.operator
, len(op_shapes
))) # :nocov:
588 def _rhs_signals(self
):
589 return union(op
._rhs
_signals
() for op
in self
.operands
)
592 return "({} {})".format(self
.operator
, " ".join(map(repr, self
.operands
)))
595 def Mux(sel
, val1
, val0
):
596 """Choose between two values.
609 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
611 sel
= Value
.cast(sel
)
614 return Operator("m", [sel
, val1
, val0
])
619 def __init__(self
, value
, start
, stop
, *, src_loc_at
=0):
620 if not isinstance(start
, int):
621 raise TypeError("Slice start must be an integer, not {!r}".format(start
))
622 if not isinstance(stop
, int):
623 raise TypeError("Slice stop must be an integer, not {!r}".format(stop
))
626 if start
not in range(-(n
+1), n
+1):
627 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start
, n
))
630 if stop
not in range(-(n
+1), n
+1):
631 raise IndexError("Cannot stop slice {} bits into {}-bit value".format(stop
, n
))
635 raise IndexError("Slice start {} must be less than slice stop {}".format(start
, stop
))
637 super().__init
__(src_loc_at
=src_loc_at
)
638 self
.value
= Value
.cast(value
)
643 return Shape(self
.stop
- self
.start
)
645 def _lhs_signals(self
):
646 return self
.value
._lhs
_signals
()
648 def _rhs_signals(self
):
649 return self
.value
._rhs
_signals
()
652 return "(slice {} {}:{})".format(repr(self
.value
), self
.start
, self
.stop
)
657 def __init__(self
, value
, offset
, width
, stride
=1, *, src_loc_at
=0):
658 if not isinstance(width
, int) or width
< 0:
659 raise TypeError("Part width must be a non-negative integer, not {!r}".format(width
))
660 if not isinstance(stride
, int) or stride
<= 0:
661 raise TypeError("Part stride must be a positive integer, not {!r}".format(stride
))
663 super().__init
__(src_loc_at
=src_loc_at
)
665 self
.offset
= Value
.cast(offset
)
670 return Shape(self
.width
)
672 def _lhs_signals(self
):
673 return self
.value
._lhs
_signals
()
675 def _rhs_signals(self
):
676 return self
.value
._rhs
_signals
() | self
.offset
._rhs
_signals
()
679 return "(part {} {} {} {})".format(repr(self
.value
), repr(self
.offset
),
680 self
.width
, self
.stride
)
685 """Concatenate values.
687 Form a compound ``Value`` from several smaller ones by concatenation.
688 The first argument occupies the lower bits of the result.
689 The return value can be used on either side of an assignment, that
690 is, the concatenated value can be used as an argument on the RHS or
691 as a target on the LHS. If it is used on the LHS, it must solely
692 consist of ``Signal`` s, slices of ``Signal`` s, and other concatenations
693 meeting these properties. The bit length of the return value is the sum of
694 the bit lengths of the arguments::
696 len(Cat(args)) == sum(len(arg) for arg in args)
700 *args : Values or iterables of Values, inout
701 ``Value`` s to be concatenated.
706 Resulting ``Value`` obtained by concatentation.
708 def __init__(self
, *args
, src_loc_at
=0):
709 super().__init
__(src_loc_at
=src_loc_at
)
710 self
.parts
= [Value
.cast(v
) for v
in flatten(args
)]
713 return Shape(sum(len(part
) for part
in self
.parts
))
715 def _lhs_signals(self
):
716 return union((part
._lhs
_signals
() for part
in self
.parts
), start
=ValueSet())
718 def _rhs_signals(self
):
719 return union((part
._rhs
_signals
() for part
in self
.parts
), start
=ValueSet())
723 for part
in reversed(self
.parts
):
725 value |
= part
._as
_const
()
729 return "(cat {})".format(" ".join(map(repr, self
.parts
)))
736 An input value is replicated (repeated) several times
737 to be used on the RHS of assignments::
739 len(Repl(s, n)) == len(s) * n
744 Input value to be replicated.
746 Number of replications.
753 def __init__(self
, value
, count
, *, src_loc_at
=0):
754 if not isinstance(count
, int) or count
< 0:
755 raise TypeError("Replication count must be a non-negative integer, not {!r}"
758 super().__init
__(src_loc_at
=src_loc_at
)
759 self
.value
= Value
.cast(value
)
763 return Shape(len(self
.value
) * self
.count
)
765 def _rhs_signals(self
):
766 return self
.value
._rhs
_signals
()
769 return "(repl {!r} {})".format(self
.value
, self
.count
)
773 class Signal(Value
, DUID
):
774 """A varying integer value.
778 shape : ``Shape``-castable object or None
779 Specification for the number of bits in this ``Signal`` and its signedness (whether it
780 can represent negative values). See ``Shape.cast`` for details.
781 If not specified, ``shape`` defaults to 1-bit and non-signed.
783 Name hint for this signal. If ``None`` (default) the name is inferred from the variable
784 name this ``Signal`` is assigned to.
785 reset : int or integral Enum
786 Reset (synchronous) or default (combinatorial) value.
787 When this ``Signal`` is assigned to in synchronous context and the corresponding clock
788 domain is reset, the ``Signal`` assumes the given value. When this ``Signal`` is unassigned
789 in combinatorial context (due to conditional assignments not being taken), the ``Signal``
790 assumes its ``reset`` value. Defaults to 0.
792 If ``True``, do not generate reset logic for this ``Signal`` in synchronous statements.
793 The ``reset`` value is only used as a combinatorial default or as the initial value.
794 Defaults to ``False``.
796 Dictionary of synthesis attributes.
797 decoder : function or Enum
798 A function converting integer signal values to human-readable strings (e.g. FSM state
799 names). If an ``Enum`` subclass is passed, it is concisely decoded using format string
800 ``"{0.name:}/{0.value:}"``, or a number if the signal value is not a member of
814 def __init__(self
, shape
=None, *, name
=None, reset
=0, reset_less
=False,
815 attrs
=None, decoder
=None, src_loc_at
=0):
816 super().__init
__(src_loc_at
=src_loc_at
)
818 if name
is not None and not isinstance(name
, str):
819 raise TypeError("Name must be a string, not {!r}".format(name
))
820 self
.name
= name
or tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$signal")
824 self
.width
, self
.signed
= Shape
.cast(shape
, src_loc_at
=1 + src_loc_at
)
826 if isinstance(reset
, Enum
):
828 if not isinstance(reset
, int):
829 raise TypeError("Reset value has to be an int or an integral Enum")
831 reset_width
= bits_for(reset
, self
.signed
)
832 if reset
!= 0 and reset_width
> self
.width
:
833 warnings
.warn("Reset value {!r} requires {} bits to represent, but the signal "
835 .format(reset
, reset_width
, self
.width
),
836 SyntaxWarning, stacklevel
=2 + src_loc_at
)
839 self
.reset_less
= bool(reset_less
)
841 self
.attrs
= OrderedDict(() if attrs
is None else attrs
)
843 if decoder
is None and isinstance(shape
, type) and issubclass(shape
, Enum
):
845 if isinstance(decoder
, type) and issubclass(decoder
, Enum
):
846 def enum_decoder(value
):
848 return "{0.name:}/{0.value:}".format(decoder(value
))
851 self
.decoder
= enum_decoder
853 self
.decoder
= decoder
855 # Not a @classmethod because nmigen.compat requires it.
857 def like(other
, *, name
=None, name_suffix
=None, src_loc_at
=0, **kwargs
):
858 """Create Signal based on another.
863 Object to base this Signal on.
867 elif name_suffix
is not None:
868 new_name
= other
.name
+ str(name_suffix
)
870 new_name
= tracer
.get_var_name(depth
=2 + src_loc_at
, default
="$like")
871 kw
= dict(shape
=Value
.cast(other
).shape(), name
=new_name
)
872 if isinstance(other
, Signal
):
873 kw
.update(reset
=other
.reset
, reset_less
=other
.reset_less
,
874 attrs
=other
.attrs
, decoder
=other
.decoder
)
876 return Signal(**kw
, src_loc_at
=1 + src_loc_at
)
879 return Shape(self
.width
, self
.signed
)
881 def _lhs_signals(self
):
882 return ValueSet((self
,))
884 def _rhs_signals(self
):
885 return ValueSet((self
,))
888 return "(sig {})".format(self
.name
)
892 class ClockSignal(Value
):
893 """Clock signal for a clock domain.
895 Any ``ClockSignal`` is equivalent to ``cd.clk`` for a clock domain with the corresponding name.
896 All of these signals ultimately refer to the same signal, but they can be manipulated
897 independently of the clock domain, even before the clock domain is created.
902 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
904 def __init__(self
, domain
="sync", *, src_loc_at
=0):
905 super().__init
__(src_loc_at
=src_loc_at
)
906 if not isinstance(domain
, str):
907 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
909 raise ValueError("Domain '{}' does not have a clock".format(domain
))
915 def _lhs_signals(self
):
916 return ValueSet((self
,))
918 def _rhs_signals(self
):
919 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
922 return "(clk {})".format(self
.domain
)
926 class ResetSignal(Value
):
927 """Reset signal for a clock domain.
929 Any ``ResetSignal`` is equivalent to ``cd.rst`` for a clock domain with the corresponding name.
930 All of these signals ultimately refer to the same signal, but they can be manipulated
931 independently of the clock domain, even before the clock domain is created.
936 Clock domain to obtain a reset signal for. Defaults to ``"sync"``.
937 allow_reset_less : bool
938 If the clock domain is reset-less, act as a constant ``0`` instead of reporting an error.
940 def __init__(self
, domain
="sync", allow_reset_less
=False, *, src_loc_at
=0):
941 super().__init
__(src_loc_at
=src_loc_at
)
942 if not isinstance(domain
, str):
943 raise TypeError("Clock domain name must be a string, not {!r}".format(domain
))
945 raise ValueError("Domain '{}' does not have a reset".format(domain
))
947 self
.allow_reset_less
= allow_reset_less
952 def _lhs_signals(self
):
953 return ValueSet((self
,))
955 def _rhs_signals(self
):
956 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
959 return "(rst {})".format(self
.domain
)
962 class Array(MutableSequence
):
963 """Addressable multiplexer.
965 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
968 The array proxy can be used as an ordinary ``Value``, i.e. participate in calculations and
969 assignments, provided that all elements of the array are values. The array proxy also supports
970 attribute access and further indexing, each returning another array proxy; this means that
971 the results of indexing into arrays, arrays of records, and arrays of arrays can all
972 be used as first-class values.
974 It is an error to change an array or any of its elements after an array proxy was created.
975 Changing the array directly will raise an exception. However, it is not possible to detect
976 the elements being modified; if an element's attribute or element is modified after the proxy
977 for it has been created, the proxy will refer to stale data.
984 gpios = Array(Signal() for _ in range(10))
986 m.d.sync += gpios[bus.addr].eq(bus.w_data)
988 m.d.sync += bus.r_data.eq(gpios[bus.addr])
990 Multidimensional array::
992 mult = Array(Array(x * y for y in range(10)) for x in range(10))
996 m.d.comb += r.eq(mult[a][b])
1004 buses = Array(Record(layout) for busno in range(4))
1005 master = Record(layout)
1007 buses[sel].r_en.eq(master.r_en),
1008 master.r_data.eq(buses[sel].r_data),
1011 def __init__(self
, iterable
=()):
1012 self
._inner
= list(iterable
)
1013 self
._proxy
_at
= None
1014 self
._mutable
= True
1016 def __getitem__(self
, index
):
1017 if isinstance(index
, Value
):
1019 self
._proxy
_at
= tracer
.get_src_loc()
1020 self
._mutable
= False
1021 return ArrayProxy(self
, index
)
1023 return self
._inner
[index
]
1026 return len(self
._inner
)
1028 def _check_mutability(self
):
1029 if not self
._mutable
:
1030 raise ValueError("Array can no longer be mutated after it was indexed with a value "
1031 "at {}:{}".format(*self
._proxy
_at
))
1033 def __setitem__(self
, index
, value
):
1034 self
._check
_mutability
()
1035 self
._inner
[index
] = value
1037 def __delitem__(self
, index
):
1038 self
._check
_mutability
()
1039 del self
._inner
[index
]
1041 def insert(self
, index
, value
):
1042 self
._check
_mutability
()
1043 self
._inner
.insert(index
, value
)
1046 return "(array{} [{}])".format(" mutable" if self
._mutable
else "",
1047 ", ".join(map(repr, self
._inner
)))
1051 class ArrayProxy(Value
):
1052 def __init__(self
, elems
, index
, *, src_loc_at
=0):
1053 super().__init
__(src_loc_at
=1 + src_loc_at
)
1055 self
.index
= Value
.cast(index
)
1057 def __getattr__(self
, attr
):
1058 return ArrayProxy([getattr(elem
, attr
) for elem
in self
.elems
], self
.index
)
1060 def __getitem__(self
, index
):
1061 return ArrayProxy([ elem
[index
] for elem
in self
.elems
], self
.index
)
1063 def _iter_as_values(self
):
1064 return (Value
.cast(elem
) for elem
in self
.elems
)
1067 width
, signed
= 0, False
1068 for elem_width
, elem_signed
in (elem
.shape() for elem
in self
._iter
_as
_values
()):
1069 width
= max(width
, elem_width
+ elem_signed
)
1070 signed
= max(signed
, elem_signed
)
1071 return Shape(width
, signed
)
1073 def _lhs_signals(self
):
1074 signals
= union((elem
._lhs
_signals
() for elem
in self
._iter
_as
_values
()), start
=ValueSet())
1077 def _rhs_signals(self
):
1078 signals
= union((elem
._rhs
_signals
() for elem
in self
._iter
_as
_values
()), start
=ValueSet())
1079 return self
.index
._rhs
_signals
() | signals
1082 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self
.elems
)), self
.index
)
1085 class UserValue(Value
):
1086 """Value with custom lowering.
1088 A ``UserValue`` is a value whose precise representation does not have to be immediately known,
1089 which is useful in certain metaprogramming scenarios. Instead of providing fixed semantics
1090 upfront, it is kept abstract for as long as possible, only being lowered to a concrete nMigen
1091 value when required.
1093 Note that the ``lower`` method will only be called once; this is necessary to ensure that
1094 nMigen's view of representation of all values stays internally consistent. If the class
1095 deriving from ``UserValue`` is mutable, then it must ensure that after ``lower`` is called,
1096 it is not mutated in a way that changes its representation.
1098 The following is an incomplete list of actions that, when applied to an ``UserValue`` directly
1099 or indirectly, will cause it to be lowered, provided as an illustrative reference:
1100 * Querying the shape using ``.shape()`` or ``len()``;
1101 * Creating a similarly shaped signal using ``Signal.like``;
1102 * Indexing or iterating through individual bits;
1103 * Adding an assignment to the value to a ``Module`` using ``m.d.<domain> +=``.
1105 def __init__(self
, *, src_loc_at
=0):
1106 super().__init
__(src_loc_at
=1 + src_loc_at
)
1107 self
.__lowered
= None
1111 """Conversion to a concrete representation."""
1114 def _lazy_lower(self
):
1115 if self
.__lowered
is None:
1116 self
.__lowered
= Value
.cast(self
.lower())
1117 return self
.__lowered
1120 return self
._lazy
_lower
().shape()
1122 def _lhs_signals(self
):
1123 return self
._lazy
_lower
()._lhs
_signals
()
1125 def _rhs_signals(self
):
1126 return self
._lazy
_lower
()._rhs
_signals
()
1130 class Sample(Value
):
1131 """Value from the past.
1133 A ``Sample`` of an expression is equal to the value of the expression ``clocks`` clock edges
1134 of the ``domain`` clock back. If that moment is before the beginning of time, it is equal
1135 to the value of the expression calculated as if each signal had its reset value.
1137 def __init__(self
, expr
, clocks
, domain
, *, src_loc_at
=0):
1138 super().__init
__(src_loc_at
=1 + src_loc_at
)
1139 self
.value
= Value
.cast(expr
)
1140 self
.clocks
= int(clocks
)
1141 self
.domain
= domain
1142 if not isinstance(self
.value
, (Const
, Signal
, ClockSignal
, ResetSignal
, Initial
)):
1143 raise TypeError("Sampled value must be a signal or a constant, not {!r}"
1144 .format(self
.value
))
1146 raise ValueError("Cannot sample a value {} cycles in the future"
1147 .format(-self
.clocks
))
1148 if not (self
.domain
is None or isinstance(self
.domain
, str)):
1149 raise TypeError("Domain name must be a string or None, not {!r}"
1150 .format(self
.domain
))
1153 return self
.value
.shape()
1155 def _rhs_signals(self
):
1156 return ValueSet((self
,))
1159 return "(sample {!r} @ {}[{}])".format(
1160 self
.value
, "<default>" if self
.domain
is None else self
.domain
, self
.clocks
)
1163 def Past(expr
, clocks
=1, domain
=None):
1164 return Sample(expr
, clocks
, domain
)
1167 def Stable(expr
, clocks
=0, domain
=None):
1168 return Sample(expr
, clocks
+ 1, domain
) == Sample(expr
, clocks
, domain
)
1171 def Rose(expr
, clocks
=0, domain
=None):
1172 return ~
Sample(expr
, clocks
+ 1, domain
) & Sample(expr
, clocks
, domain
)
1175 def Fell(expr
, clocks
=0, domain
=None):
1176 return Sample(expr
, clocks
+ 1, domain
) & ~
Sample(expr
, clocks
, domain
)
1180 class Initial(Value
):
1181 """Start indicator, for model checking.
1183 An ``Initial`` signal is ``1`` at the first cycle of model checking, and ``0`` at any other.
1185 def __init__(self
, *, src_loc_at
=0):
1186 super().__init
__(src_loc_at
=1 + src_loc_at
)
1191 def _rhs_signals(self
):
1192 return ValueSet((self
,))
1198 class _StatementList(list):
1200 return "({})".format(" ".join(map(repr, self
)))
1204 def __init__(self
, *, src_loc_at
=0):
1205 self
.src_loc
= tracer
.get_src_loc(1 + src_loc_at
)
1209 if isinstance(obj
, Iterable
):
1210 return _StatementList(sum((Statement
.cast(e
) for e
in obj
), []))
1212 if isinstance(obj
, Statement
):
1213 return _StatementList([obj
])
1215 raise TypeError("Object {!r} is not an nMigen statement".format(obj
))
1219 class Assign(Statement
):
1220 def __init__(self
, lhs
, rhs
, *, src_loc_at
=0):
1221 super().__init
__(src_loc_at
=src_loc_at
)
1222 self
.lhs
= Value
.cast(lhs
)
1223 self
.rhs
= Value
.cast(rhs
)
1225 def _lhs_signals(self
):
1226 return self
.lhs
._lhs
_signals
()
1228 def _rhs_signals(self
):
1229 return self
.lhs
._rhs
_signals
() | self
.rhs
._rhs
_signals
()
1232 return "(eq {!r} {!r})".format(self
.lhs
, self
.rhs
)
1235 class UnusedProperty(UnusedMustUse
):
1239 class Property(Statement
, MustUse
):
1240 _MustUse__warning
= UnusedProperty
1242 def __init__(self
, test
, *, _check
=None, _en
=None, src_loc_at
=0):
1243 super().__init
__(src_loc_at
=src_loc_at
)
1244 self
.test
= Value
.cast(test
)
1245 self
._check
= _check
1247 if self
._check
is None:
1248 self
._check
= Signal(reset_less
=True, name
="${}$check".format(self
._kind
))
1249 self
._check
.src_loc
= self
.src_loc
1251 self
._en
= Signal(reset_less
=True, name
="${}$en".format(self
._kind
))
1252 self
._en
.src_loc
= self
.src_loc
1254 def _lhs_signals(self
):
1255 return ValueSet((self
._en
, self
._check
))
1257 def _rhs_signals(self
):
1258 return self
.test
._rhs
_signals
()
1261 return "({} {!r})".format(self
._kind
, self
.test
)
1265 class Assert(Property
):
1270 class Assume(Property
):
1275 class Cover(Property
):
1280 class Switch(Statement
):
1281 def __init__(self
, test
, cases
, *, src_loc
=None, src_loc_at
=0, case_src_locs
={}):
1283 super().__init
__(src_loc_at
=src_loc_at
)
1285 # Switch is a bit special in terms of location tracking because it is usually created
1286 # long after the control has left the statement that directly caused its creation.
1287 self
.src_loc
= src_loc
1288 # Switch is also a bit special in that its parts also have location information. It can't
1289 # be automatically traced, so whatever constructs a Switch may optionally provide it.
1290 self
.case_src_locs
= {}
1292 self
.test
= Value
.cast(test
)
1293 self
.cases
= OrderedDict()
1294 for orig_keys
, stmts
in cases
.items():
1295 # Map: None -> (); key -> (key,); (key...) -> (key...)
1299 if not isinstance(keys
, tuple):
1301 # Map: 2 -> "0010"; "0010" -> "0010"
1304 if isinstance(key
, str):
1305 key
= "".join(key
.split()) # remove whitespace
1306 elif isinstance(key
, int):
1307 key
= format(key
, "b").rjust(len(self
.test
), "0")
1308 elif isinstance(key
, Enum
):
1309 key
= format(key
.value
, "b").rjust(len(self
.test
), "0")
1311 raise TypeError("Object {!r} cannot be used as a switch key"
1313 assert len(key
) == len(self
.test
)
1314 new_keys
= (*new_keys
, key
)
1315 if not isinstance(stmts
, Iterable
):
1317 self
.cases
[new_keys
] = Statement
.cast(stmts
)
1318 if orig_keys
in case_src_locs
:
1319 self
.case_src_locs
[new_keys
] = case_src_locs
[orig_keys
]
1321 def _lhs_signals(self
):
1322 signals
= union((s
._lhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1326 def _rhs_signals(self
):
1327 signals
= union((s
._rhs
_signals
() for ss
in self
.cases
.values() for s
in ss
),
1329 return self
.test
._rhs
_signals
() | signals
1332 def case_repr(keys
, stmts
):
1333 stmts_repr
= " ".join(map(repr, stmts
))
1335 return "(default {})".format(stmts_repr
)
1336 elif len(keys
) == 1:
1337 return "(case {} {})".format(keys
[0], stmts_repr
)
1339 return "(case ({}) {})".format(" ".join(keys
), stmts_repr
)
1340 case_reprs
= [case_repr(keys
, stmts
) for keys
, stmts
in self
.cases
.items()]
1341 return "(switch {!r} {})".format(self
.test
, " ".join(case_reprs
))
1344 class _MappedKeyCollection(metaclass
=ABCMeta
):
1346 def _map_key(self
, key
):
1350 def _unmap_key(self
, key
):
1354 class _MappedKeyDict(MutableMapping
, _MappedKeyCollection
):
1355 def __init__(self
, pairs
=()):
1356 self
._storage
= OrderedDict()
1357 for key
, value
in pairs
:
1360 def __getitem__(self
, key
):
1361 key
= None if key
is None else self
._map
_key
(key
)
1362 return self
._storage
[key
]
1364 def __setitem__(self
, key
, value
):
1365 key
= None if key
is None else self
._map
_key
(key
)
1366 self
._storage
[key
] = value
1368 def __delitem__(self
, key
):
1369 key
= None if key
is None else self
._map
_key
(key
)
1370 del self
._storage
[key
]
1373 for key
in self
._storage
:
1377 yield self
._unmap
_key
(key
)
1379 def __eq__(self
, other
):
1380 if not isinstance(other
, type(self
)):
1382 if len(self
) != len(other
):
1384 for ak
, bk
in zip(sorted(self
._storage
), sorted(other
._storage
)):
1387 if self
._storage
[ak
] != other
._storage
[bk
]:
1392 return len(self
._storage
)
1395 pairs
= ["({!r}, {!r})".format(k
, v
) for k
, v
in self
.items()]
1396 return "{}.{}([{}])".format(type(self
).__module
__, type(self
).__name
__,
1400 class _MappedKeySet(MutableSet
, _MappedKeyCollection
):
1401 def __init__(self
, elements
=()):
1402 self
._storage
= OrderedDict()
1403 for elem
in elements
:
1406 def add(self
, value
):
1407 self
._storage
[self
._map
_key
(value
)] = None
1409 def update(self
, values
):
1410 for value
in values
:
1413 def discard(self
, value
):
1415 del self
._storage
[self
._map
_key
(value
)]
1417 def __contains__(self
, value
):
1418 return self
._map
_key
(value
) in self
._storage
1421 for key
in [k
for k
in self
._storage
]:
1422 yield self
._unmap
_key
(key
)
1425 return len(self
._storage
)
1428 return "{}.{}({})".format(type(self
).__module
__, type(self
).__name
__,
1429 ", ".join(repr(x
) for x
in self
))
1433 def __init__(self
, value
):
1434 self
.value
= Value
.cast(value
)
1435 if isinstance(self
.value
, Const
):
1436 self
._hash
= hash(self
.value
.value
)
1437 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1438 self
._hash
= hash(self
.value
.duid
)
1439 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1440 self
._hash
= hash(self
.value
.domain
)
1441 elif isinstance(self
.value
, Operator
):
1442 self
._hash
= hash((self
.value
.operator
,
1443 tuple(ValueKey(o
) for o
in self
.value
.operands
)))
1444 elif isinstance(self
.value
, Slice
):
1445 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.start
, self
.value
.stop
))
1446 elif isinstance(self
.value
, Part
):
1447 self
._hash
= hash((ValueKey(self
.value
.value
), ValueKey(self
.value
.offset
),
1448 self
.value
.width
, self
.value
.stride
))
1449 elif isinstance(self
.value
, Cat
):
1450 self
._hash
= hash(tuple(ValueKey(o
) for o
in self
.value
.parts
))
1451 elif isinstance(self
.value
, ArrayProxy
):
1452 self
._hash
= hash((ValueKey(self
.value
.index
),
1453 tuple(ValueKey(e
) for e
in self
.value
._iter
_as
_values
())))
1454 elif isinstance(self
.value
, Sample
):
1455 self
._hash
= hash((ValueKey(self
.value
.value
), self
.value
.clocks
, self
.value
.domain
))
1456 elif isinstance(self
.value
, Initial
):
1459 raise TypeError("Object {!r} cannot be used as a key in value collections"
1460 .format(self
.value
))
1465 def __eq__(self
, other
):
1466 if type(other
) is not ValueKey
:
1468 if type(self
.value
) is not type(other
.value
):
1471 if isinstance(self
.value
, Const
):
1472 return self
.value
.value
== other
.value
.value
1473 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1474 return self
.value
is other
.value
1475 elif isinstance(self
.value
, (ClockSignal
, ResetSignal
)):
1476 return self
.value
.domain
== other
.value
.domain
1477 elif isinstance(self
.value
, Operator
):
1478 return (self
.value
.operator
== other
.value
.operator
and
1479 len(self
.value
.operands
) == len(other
.value
.operands
) and
1480 all(ValueKey(a
) == ValueKey(b
)
1481 for a
, b
in zip(self
.value
.operands
, other
.value
.operands
)))
1482 elif isinstance(self
.value
, Slice
):
1483 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1484 self
.value
.start
== other
.value
.start
and
1485 self
.value
.stop
== other
.value
.stop
)
1486 elif isinstance(self
.value
, Part
):
1487 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1488 ValueKey(self
.value
.offset
) == ValueKey(other
.value
.offset
) and
1489 self
.value
.width
== other
.value
.width
and
1490 self
.value
.stride
== other
.value
.stride
)
1491 elif isinstance(self
.value
, Cat
):
1492 return all(ValueKey(a
) == ValueKey(b
)
1493 for a
, b
in zip(self
.value
.parts
, other
.value
.parts
))
1494 elif isinstance(self
.value
, ArrayProxy
):
1495 return (ValueKey(self
.value
.index
) == ValueKey(other
.value
.index
) and
1496 len(self
.value
.elems
) == len(other
.value
.elems
) and
1497 all(ValueKey(a
) == ValueKey(b
)
1498 for a
, b
in zip(self
.value
._iter
_as
_values
(),
1499 other
.value
._iter
_as
_values
())))
1500 elif isinstance(self
.value
, Sample
):
1501 return (ValueKey(self
.value
.value
) == ValueKey(other
.value
.value
) and
1502 self
.value
.clocks
== other
.value
.clocks
and
1503 self
.value
.domain
== self
.value
.domain
)
1504 elif isinstance(self
.value
, Initial
):
1507 raise TypeError("Object {!r} cannot be used as a key in value collections"
1508 .format(self
.value
))
1510 def __lt__(self
, other
):
1511 if not isinstance(other
, ValueKey
):
1513 if type(self
.value
) != type(other
.value
):
1516 if isinstance(self
.value
, Const
):
1517 return self
.value
< other
.value
1518 elif isinstance(self
.value
, (Signal
, AnyValue
)):
1519 return self
.value
.duid
< other
.value
.duid
1520 elif isinstance(self
.value
, Slice
):
1521 return (ValueKey(self
.value
.value
) < ValueKey(other
.value
.value
) and
1522 self
.value
.start
< other
.value
.start
and
1523 self
.value
.end
< other
.value
.end
)
1525 raise TypeError("Object {!r} cannot be used as a key in value collections")
1528 return "<{}.ValueKey {!r}>".format(__name__
, self
.value
)
1531 class ValueDict(_MappedKeyDict
):
1533 _unmap_key
= lambda self
, key
: key
.value
1536 class ValueSet(_MappedKeySet
):
1538 _unmap_key
= lambda self
, key
: key
.value
1542 def __init__(self
, signal
):
1543 self
.signal
= signal
1544 if isinstance(signal
, Signal
):
1545 self
._intern
= (0, signal
.duid
)
1546 elif type(signal
) is ClockSignal
:
1547 self
._intern
= (1, signal
.domain
)
1548 elif type(signal
) is ResetSignal
:
1549 self
._intern
= (2, signal
.domain
)
1551 raise TypeError("Object {!r} is not an nMigen signal".format(signal
))
1554 return hash(self
._intern
)
1556 def __eq__(self
, other
):
1557 if type(other
) is not SignalKey
:
1559 return self
._intern
== other
._intern
1561 def __lt__(self
, other
):
1562 if type(other
) is not SignalKey
:
1563 raise TypeError("Object {!r} cannot be compared to a SignalKey".format(signal
))
1564 return self
._intern
< other
._intern
1567 return "<{}.SignalKey {!r}>".format(__name__
, self
.signal
)
1570 class SignalDict(_MappedKeyDict
):
1571 _map_key
= SignalKey
1572 _unmap_key
= lambda self
, key
: key
.signal
1575 class SignalSet(_MappedKeySet
):
1576 _map_key
= SignalKey
1577 _unmap_key
= lambda self
, key
: key
.signal