hdl.ast: Cat.{operands→parts}
[nmigen.git] / nmigen / hdl / ast.py
1 from abc import ABCMeta, abstractmethod
2 import builtins
3 import traceback
4 from collections import OrderedDict
5 from collections.abc import Iterable, MutableMapping, MutableSet, MutableSequence
6
7 from .. import tracer
8 from ..tools import *
9
10
11 __all__ = [
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",
17 ]
18
19
20 class DUID:
21 """Deterministic Unique IDentifier"""
22 __next_uid = 0
23 def __init__(self):
24 self.duid = DUID.__next_uid
25 DUID.__next_uid += 1
26
27
28 class Value(metaclass=ABCMeta):
29 @staticmethod
30 def wrap(obj):
31 """Ensures that the passed object is an nMigen value. Booleans and integers
32 are automatically wrapped into ``Const``."""
33 if isinstance(obj, Value):
34 return obj
35 elif isinstance(obj, (bool, int)):
36 return Const(obj)
37 else:
38 raise TypeError("Object '{!r}' is not an nMigen value".format(obj))
39
40 def __init__(self, src_loc_at=0):
41 super().__init__()
42
43 tb = traceback.extract_stack(limit=3 + src_loc_at)
44 if len(tb) < src_loc_at:
45 self.src_loc = None
46 else:
47 self.src_loc = (tb[0].filename, tb[0].lineno)
48
49 def __bool__(self):
50 raise TypeError("Attempted to convert nMigen value to boolean")
51
52 def __invert__(self):
53 return Operator("~", [self])
54 def __neg__(self):
55 return Operator("-", [self])
56
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])
97
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])
110
111 def __len__(self):
112 return self.shape()[0]
113
114 def __getitem__(self, key):
115 n = len(self)
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))
119 if key < 0:
120 key += n
121 return Slice(self, key, key + 1)
122 elif isinstance(key, slice):
123 start, stop, step = key.indices(n)
124 if step != 1:
125 return Cat(self[i] for i in range(start, stop, step))
126 return Slice(self, start, stop)
127 else:
128 raise TypeError("Cannot index value with {}".format(repr(key)))
129
130 def bool(self):
131 """Conversion to boolean.
132
133 Returns
134 -------
135 Value, out
136 Output ``Value``. If any bits are set, returns ``1``, else ``0``.
137 """
138 return Operator("b", [self])
139
140 def part(self, offset, width):
141 """Indexed part-select.
142
143 Selects a constant width but variable offset part of a ``Value``.
144
145 Parameters
146 ----------
147 offset : Value, in
148 start point of the selected bits
149 width : int
150 number of selected bits
151
152 Returns
153 -------
154 Part, out
155 Selected part of the ``Value``
156 """
157 return Part(self, offset, width)
158
159 def eq(self, value):
160 """Assignment.
161
162 Parameters
163 ----------
164 value : Value, in
165 Value to be assigned.
166
167 Returns
168 -------
169 Assign
170 Assignment statement that can be used in combinatorial or synchronous context.
171 """
172 return Assign(self, value)
173
174 @abstractmethod
175 def shape(self):
176 """Bit length and signedness of a value.
177
178 Returns
179 -------
180 int, bool
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).
183
184 Examples
185 --------
186 >>> Value.shape(Signal(8))
187 8, False
188 >>> Value.shape(C(0xaa))
189 8, False
190 """
191 pass # :nocov:
192
193 def _lhs_signals(self):
194 raise TypeError("Value {!r} cannot be used in assignments".format(self))
195
196 @abstractmethod
197 def _rhs_signals(self):
198 pass # :nocov:
199
200 __hash__ = None
201
202
203 class Const(Value):
204 """A constant, literal integer value.
205
206 Parameters
207 ----------
208 value : int
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`.
214
215 Attributes
216 ----------
217 nbits : int
218 signed : bool
219 """
220 src_loc = None
221
222 @staticmethod
223 def normalize(value, shape):
224 nbits, signed = shape
225 mask = (1 << nbits) - 1
226 value &= mask
227 if signed and value >> (nbits - 1):
228 value |= ~mask
229 return value
230
231 def __init__(self, value, shape=None):
232 self.value = int(value)
233 if shape is None:
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)
241
242 def shape(self):
243 return self.nbits, self.signed
244
245 def _rhs_signals(self):
246 return ValueSet()
247
248 def __repr__(self):
249 return "(const {}'{}d{})".format(self.nbits, "s" if self.signed else "", self.value)
250
251
252 C = Const # shorthand
253
254
255 class Operator(Value):
256 def __init__(self, op, operands, src_loc_at=0):
257 super().__init__(src_loc_at=1 + src_loc_at)
258 self.op = op
259 self.operands = [Value.wrap(o) for o in operands]
260
261 @staticmethod
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
274 else:
275 # first signed, second operand unsigned (add sign bit)
276 return max(a_bits, b_bits + 1), True
277
278 def shape(self):
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
284 if self.op == "-":
285 if not a_sign:
286 return a_bits + 1, True
287 else:
288 return a_bits, a_sign
289 if self.op == "b":
290 return 1, False
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
296 if self.op == "*":
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"):
306 return 1, False
307 if self.op in ("&", "^", "|"):
308 return self._bitwise_binary_shape(*op_shapes)
309 if self.op == "<<":
310 if b_sign:
311 extra = 2 ** (b_bits - 1) - 1
312 else:
313 extra = 2 ** (b_bits) - 1
314 return a_bits + extra, a_sign
315 if self.op == ">>":
316 if b_sign:
317 extra = 2 ** (b_bits - 1)
318 else:
319 extra = 0
320 return a_bits + extra, a_sign
321 elif len(op_shapes) == 3:
322 if self.op == "m":
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:
327
328 def _rhs_signals(self):
329 return union(op._rhs_signals() for op in self.operands)
330
331 def __repr__(self):
332 return "({} {})".format(self.op, " ".join(map(repr, self.operands)))
333
334
335 def Mux(sel, val1, val0):
336 """Choose between two values.
337
338 Parameters
339 ----------
340 sel : Value, in
341 Selector.
342 val1 : Value, in
343 val0 : Value, in
344 Input values.
345
346 Returns
347 -------
348 Value, out
349 Output ``Value``. If ``sel`` is asserted, the Mux returns ``val1``, else ``val0``.
350 """
351 return Operator("m", [sel, val1, val0], src_loc_at=1)
352
353
354 class Slice(Value):
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))
360
361 n = len(value)
362 if start not in range(-n, n):
363 raise IndexError("Cannot start slice {} bits into {}-bit value".format(start, n))
364 if start < 0:
365 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))
368 if end < 0:
369 end += n
370 if start > end:
371 raise IndexError("Slice start {} must be less than slice end {}".format(start, end))
372
373 super().__init__()
374 self.value = Value.wrap(value)
375 self.start = start
376 self.end = end
377
378 def shape(self):
379 return self.end - self.start, False
380
381 def _lhs_signals(self):
382 return self.value._lhs_signals()
383
384 def _rhs_signals(self):
385 return self.value._rhs_signals()
386
387 def __repr__(self):
388 return "(slice {} {}:{})".format(repr(self.value), self.start, self.end)
389
390
391 class Part(Value):
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))
395
396 super().__init__()
397 self.value = value
398 self.offset = Value.wrap(offset)
399 self.width = width
400
401 def shape(self):
402 return self.width, False
403
404 def _lhs_signals(self):
405 return self.value._lhs_signals()
406
407 def _rhs_signals(self):
408 return self.value._rhs_signals() | self.offset._rhs_signals()
409
410 def __repr__(self):
411 return "(part {} {} {})".format(repr(self.value), repr(self.offset), self.width)
412
413
414 class Cat(Value):
415 """Concatenate values.
416
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::
425
426 len(Cat(args)) == sum(len(arg) for arg in args)
427
428 Parameters
429 ----------
430 *args : Values or iterables of Values, inout
431 ``Value`` s to be concatenated.
432
433 Returns
434 -------
435 Value, inout
436 Resulting ``Value`` obtained by concatentation.
437 """
438 def __init__(self, *args):
439 super().__init__()
440 self.parts = [Value.wrap(v) for v in flatten(args)]
441
442 def shape(self):
443 return sum(len(op) for op in self.parts), False
444
445 def _lhs_signals(self):
446 return union(op._lhs_signals() for op in self.parts)
447
448 def _rhs_signals(self):
449 return union(op._rhs_signals() for op in self.parts)
450
451 def __repr__(self):
452 return "(cat {})".format(" ".join(map(repr, self.parts)))
453
454
455 class Repl(Value):
456 """Replicate a value
457
458 An input value is replicated (repeated) several times
459 to be used on the RHS of assignments::
460
461 len(Repl(s, n)) == len(s) * n
462
463 Parameters
464 ----------
465 value : Value, in
466 Input value to be replicated.
467 count : int
468 Number of replications.
469
470 Returns
471 -------
472 Repl, out
473 Replicated value.
474 """
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}'"
478 .format(count))
479
480 super().__init__()
481 self.value = Value.wrap(value)
482 self.count = count
483
484 def shape(self):
485 return len(self.value) * self.count, False
486
487 def _rhs_signals(self):
488 return self.value._rhs_signals()
489
490 def __repr__(self):
491 return "(repl {!r} {})".format(self.value, self.count)
492
493
494 class Signal(Value, DUID):
495 """A varying integer value.
496
497 Parameters
498 ----------
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.
503 name : str
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
507 sequences.
508 reset : int
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.
514 reset_less : bool
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``.
518 min : int or None
519 max : int or None
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).
523 attrs : dict
524 Dictionary of synthesis attributes.
525 decoder : function
526 A function converting integer signal values to human-readable strings (e.g. FSM state
527 names).
528
529 Attributes
530 ----------
531 nbits : int
532 signed : bool
533 name : str
534 reset : int
535 reset_less : bool
536 attrs : dict
537 """
538
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)
542
543 if name is None:
544 try:
545 name = tracer.get_var_name(depth=2 + src_loc_at)
546 except tracer.NameNotFound:
547 name = "$signal"
548 self.name = name
549
550 if shape is None:
551 if min is None:
552 min = 0
553 if max is None:
554 max = 2
555 max -= 1 # make both bounds inclusive
556 if not min < max:
557 raise ValueError("Lower bound {} should be less than higher bound {}"
558 .format(min, max))
559 self.signed = min < 0 or max < 0
560 self.nbits = builtins.max(bits_for(min, self.signed), bits_for(max, self.signed))
561
562 else:
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
567 else:
568 self.nbits, self.signed = shape
569
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)
574
575 self.attrs = OrderedDict(() if attrs is None else attrs)
576 self.decoder = decoder
577
578 @classmethod
579 def like(cls, other, src_loc_at=0, **kwargs):
580 """Create Signal based on another.
581
582 Parameters
583 ----------
584 other : Value
585 Object to base this Signal on.
586 """
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)
592 kw.update(kwargs)
593 return cls(**kw, src_loc_at=1 + src_loc_at)
594
595 def shape(self):
596 return self.nbits, self.signed
597
598 def _lhs_signals(self):
599 return ValueSet((self,))
600
601 def _rhs_signals(self):
602 return ValueSet((self,))
603
604 def __repr__(self):
605 return "(sig {})".format(self.name)
606
607
608 class ClockSignal(Value):
609 """Clock signal for a clock domain.
610
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.
614
615 Parameters
616 ----------
617 domain : str
618 Clock domain to obtain a clock signal for. Defaults to ``"sync"``.
619 """
620 def __init__(self, domain="sync"):
621 super().__init__()
622 if not isinstance(domain, str):
623 raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain))
624 self.domain = domain
625
626 def shape(self):
627 return 1, False
628
629 def _rhs_signals(self):
630 raise NotImplementedError("ClockSignal must be lowered to a concrete signal") # :nocov:
631
632 def __repr__(self):
633 return "(clk {})".format(self.domain)
634
635
636 class ResetSignal(Value):
637 """Reset signal for a clock domain.
638
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.
642
643 Parameters
644 ----------
645 domain : str
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.
649 """
650 def __init__(self, domain="sync", allow_reset_less=False):
651 super().__init__()
652 if not isinstance(domain, str):
653 raise TypeError("Clock domain name must be a string, not '{!r}'".format(domain))
654 self.domain = domain
655 self.allow_reset_less = allow_reset_less
656
657 def shape(self):
658 return 1, False
659
660 def _rhs_signals(self):
661 raise NotImplementedError("ResetSignal must be lowered to a concrete signal") # :nocov:
662
663 def __repr__(self):
664 return "(rst {})".format(self.domain)
665
666
667 class Array(MutableSequence):
668 """Addressable multiplexer.
669
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
671 in a proxy.
672
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.
678
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.
683
684 Examples
685 --------
686
687 Simple array::
688
689 gpios = Array(Signal() for _ in range(10))
690 with m.If(bus.we):
691 m.d.sync += gpios[bus.adr].eq(bus.dat_w)
692 with m.Else():
693 m.d.sync += bus.dat_r.eq(gpios[bus.adr])
694
695 Multidimensional array::
696
697 mult = Array(Array(x * y for y in range(10)) for x in range(10))
698 a = Signal(max=10)
699 b = Signal(max=10)
700 r = Signal(8)
701 m.d.comb += r.eq(mult[a][b])
702
703 Array of records::
704
705 layout = [
706 ("re", 1),
707 ("dat_r", 16),
708 ]
709 buses = Array(Record(layout) for busno in range(4))
710 master = Record(layout)
711 m.d.comb += [
712 buses[sel].re.eq(master.re),
713 master.dat_r.eq(buses[sel].dat_r),
714 ]
715 """
716 def __init__(self, iterable=()):
717 self._inner = list(iterable)
718 self._proxy_at = None
719 self._mutable = True
720
721 def __getitem__(self, index):
722 if isinstance(index, Value):
723 if self._mutable:
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)
728 else:
729 return self._inner[index]
730
731 def __len__(self):
732 return len(self._inner)
733
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))
738
739 def __setitem__(self, index, value):
740 self._check_mutability()
741 self._inner[index] = value
742
743 def __delitem__(self, index):
744 self._check_mutability()
745 del self._inner[index]
746
747 def insert(self, index, value):
748 self._check_mutability()
749 self._inner.insert(index, value)
750
751 def __repr__(self):
752 return "(array{} [{}])".format(" mutable" if self._mutable else "",
753 ", ".join(map(repr, self._inner)))
754
755
756 class ArrayProxy(Value):
757 def __init__(self, elems, index):
758 super().__init__(src_loc_at=1)
759 self.elems = elems
760 self.index = Value.wrap(index)
761
762 def __getattr__(self, attr):
763 return ArrayProxy([getattr(elem, attr) for elem in self.elems], self.index)
764
765 def __getitem__(self, index):
766 return ArrayProxy([ elem[index] for elem in self.elems], self.index)
767
768 def _iter_as_values(self):
769 return (Value.wrap(elem) for elem in self.elems)
770
771 def shape(self):
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)
776 return bits, sign
777
778 def _lhs_signals(self):
779 signals = union((elem._lhs_signals() for elem in self._iter_as_values()), start=ValueSet())
780 return signals
781
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
785
786 def __repr__(self):
787 return "(proxy (array [{}]) {!r})".format(", ".join(map(repr, self.elems)), self.index)
788
789
790 class _StatementList(list):
791 def __repr__(self):
792 return "({})".format(" ".join(map(repr, self)))
793
794
795 class Statement:
796 @staticmethod
797 def wrap(obj):
798 if isinstance(obj, Iterable):
799 return _StatementList(sum((Statement.wrap(e) for e in obj), []))
800 else:
801 if isinstance(obj, Statement):
802 return _StatementList([obj])
803 else:
804 raise TypeError("Object '{!r}' is not an nMigen statement".format(obj))
805
806
807 class Assign(Statement):
808 def __init__(self, lhs, rhs):
809 self.lhs = Value.wrap(lhs)
810 self.rhs = Value.wrap(rhs)
811
812 def _lhs_signals(self):
813 return self.lhs._lhs_signals()
814
815 def _rhs_signals(self):
816 return self.lhs._rhs_signals() | self.rhs._rhs_signals()
817
818 def __repr__(self):
819 return "(eq {!r} {!r})".format(self.lhs, self.rhs)
820
821
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)
831 else:
832 raise TypeError("Object '{!r}' cannot be used as a switch key"
833 .format(key))
834 if not isinstance(stmts, Iterable):
835 stmts = [stmts]
836 self.cases[key] = Statement.wrap(stmts)
837
838 def _lhs_signals(self):
839 signals = union((s._lhs_signals() for ss in self.cases.values() for s in ss),
840 start=ValueSet())
841 return signals
842
843 def _rhs_signals(self):
844 signals = union((s._rhs_signals() for ss in self.cases.values() for s in ss),
845 start=ValueSet())
846 return self.test._rhs_signals() | signals
847
848 def __repr__(self):
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))
852
853
854 class Delay(Statement):
855 def __init__(self, interval=None):
856 self.interval = None if interval is None else float(interval)
857
858 def _rhs_signals(self):
859 return ValueSet()
860
861 def __repr__(self):
862 if self.interval is None:
863 return "(delay ε)"
864 else:
865 return "(delay {:.3}us)".format(self.interval * 10e6)
866
867
868 class Tick(Statement):
869 def __init__(self, domain):
870 self.domain = str(domain)
871
872 def _rhs_signals(self):
873 return ValueSet()
874
875 def __repr__(self):
876 return "(tick {})".format(self.domain)
877
878
879 class Passive(Statement):
880 def _rhs_signals(self):
881 return ValueSet()
882
883 def __repr__(self):
884 return "(passive)"
885
886
887 class _MappedKeyCollection(metaclass=ABCMeta):
888 @abstractmethod
889 def _map_key(self, key):
890 pass # :nocov:
891
892 @abstractmethod
893 def _unmap_key(self, key):
894 pass # :nocov:
895
896
897 class _MappedKeyDict(MutableMapping, _MappedKeyCollection):
898 def __init__(self, pairs=()):
899 self._storage = OrderedDict()
900 for key, value in pairs:
901 self[key] = value
902
903 def __getitem__(self, key):
904 key = None if key is None else self._map_key(key)
905 return self._storage[key]
906
907 def __setitem__(self, key, value):
908 key = None if key is None else self._map_key(key)
909 self._storage[key] = value
910
911 def __delitem__(self, key):
912 key = None if key is None else self._map_key(key)
913 del self._storage[key]
914
915 def __iter__(self):
916 for key in self._storage:
917 if key is None:
918 yield None
919 else:
920 yield self._unmap_key(key)
921
922 def __eq__(self, other):
923 if not isinstance(other, type(self)):
924 return False
925 if len(self) != len(other):
926 return False
927 for ak, bk in zip(sorted(self._storage), sorted(other._storage)):
928 if ak != bk:
929 return False
930 if self._storage[ak] != other._storage[bk]:
931 return False
932 return True
933
934 def __len__(self):
935 return len(self._storage)
936
937 def __repr__(self):
938 pairs = ["({!r}, {!r})".format(k, v) for k, v in self.items()]
939 return "{}.{}([{}])".format(type(self).__module__, type(self).__name__,
940 ", ".join(pairs))
941
942
943 class _MappedKeySet(MutableSet, _MappedKeyCollection):
944 def __init__(self, elements=()):
945 self._storage = OrderedDict()
946 for elem in elements:
947 self.add(elem)
948
949 def add(self, value):
950 self._storage[self._map_key(value)] = None
951
952 def update(self, values):
953 for value in values:
954 self.add(value)
955
956 def discard(self, value):
957 if value in self:
958 del self._storage[self._map_key(value)]
959
960 def __contains__(self, value):
961 return self._map_key(value) in self._storage
962
963 def __iter__(self):
964 for key in [k for k in self._storage]:
965 yield self._unmap_key(key)
966
967 def __len__(self):
968 return len(self._storage)
969
970 def __repr__(self):
971 return "{}.{}({})".format(type(self).__module__, type(self).__name__,
972 ", ".join(repr(x) for x in self))
973
974
975 class ValueKey:
976 def __init__(self, value):
977 self.value = Value.wrap(value)
978
979 def __hash__(self):
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),
990 self.value.width))
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())))
996 else: # :nocov:
997 raise TypeError("Object '{!r}' cannot be used as a key in value collections"
998 .format(self.value))
999
1000 def __eq__(self, other):
1001 if type(other) is not ValueKey:
1002 return False
1003 if type(self.value) is not type(other.value):
1004 return False
1005
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())))
1032 else: # :nocov:
1033 raise TypeError("Object '{!r}' cannot be used as a key in value collections"
1034 .format(self.value))
1035
1036 def __lt__(self, other):
1037 if not isinstance(other, ValueKey):
1038 return False
1039 if type(self.value) != type(other.value):
1040 return False
1041
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)
1050 else: # :nocov:
1051 raise TypeError("Object '{!r}' cannot be used as a key in value collections")
1052
1053 def __repr__(self):
1054 return "<{}.ValueKey {!r}>".format(__name__, self.value)
1055
1056
1057 class ValueDict(_MappedKeyDict):
1058 _map_key = ValueKey
1059 _unmap_key = lambda self, key: key.value
1060
1061
1062 class ValueSet(_MappedKeySet):
1063 _map_key = ValueKey
1064 _unmap_key = lambda self, key: key.value
1065
1066
1067 class SignalKey:
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
1072
1073 def __hash__(self):
1074 return hash(self.signal.duid)
1075
1076 def __eq__(self, other):
1077 if type(other) is not SignalKey:
1078 return False
1079 return self.signal is other.signal
1080
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
1085
1086 def __repr__(self):
1087 return "<{}.SignalKey {!r}>".format(__name__, self.signal)
1088
1089
1090 class SignalDict(_MappedKeyDict):
1091 _map_key = SignalKey
1092 _unmap_key = lambda self, key: key.signal
1093
1094
1095 class SignalSet(_MappedKeySet):
1096 _map_key = SignalKey
1097 _unmap_key = lambda self, key: key.signal