# Language reference

Warning

This reference is a work in progress and is seriously incomplete!

While the wording below states that anything not described in this document isn’t covered by the backwards compatibility guarantee, this should be ignored until the document is complete and this warning is removed.

This reference describes the Python classes that underlie the Amaranth language’s syntax. It assumes familiarity with the language guide.

## Backwards compatibility

As part of the Amaranth backwards compatibility guarantee, any behaviors described in this document will not change from a version to another without at least one version including a warning about the impending change. Any nontrivial change to these behaviors must also go through the public review as a part of the Amaranth Request for Comments process.

Conversely, any behavior not documented here is subject to change at any time with or without notice, and any names under the `amaranth.hdl` module that are not explicitly included in this document, even if they do not begin with an underscore, are internal to the implementation of the language.

## Importing syntax

There are two ways to import the Amaranth syntax into a Python file: by importing the prelude or by importing individual names from the `amaranth.hdl` module. Since the prelude is kept small and rarely extended to avoid breaking downstream code that uses a glob import, there are some names that are only exported from the `amaranth.hdl` module. The following three snippets are equivalent:

    from amaranth import *

    m = Module()

    import amaranth as am

    m = am.Module()

    from amaranth.hdl import Module

    m = Module()

The prelude exports exactly the following names:

- `Shape`

- `unsigned()`

- `signed()`

- `Value`

- `Const`

- `C()`

- `Mux()`

- `Cat()`

- `Array`

- `Signal`

- `ClockSignal`

- `ResetSignal`

- `Format`

- `Print`

- `Assert()`

- `Module`

- `ClockDomain`

- `Elaboratable`

- `Fragment`

- `Instance`

- `Memory`

- `Record` (deprecated)

- `DomainRenamer`

- `ResetInserter`

- `EnableInserter`

## Source locations

Many functions and methods in Amaranth take the `src_loc_at=0` keyword argument. These language constructs may inspect the call stack to determine the file and line of its call site, which will be used to annotate generated code when a netlist is generated or to improve diagnostic messages.

Some call sites are not relevant for an Amaranth designer; e.g. when an Amaranth language construct is called from a user-defined utility function, the source location of the call site within this utility function is usually not interesting to the designer. In these cases, one or more levels of function calls can be removed from consideration using the `src_loc_at` argument as follows (using `Shape.cast()` to demonstrate the concept):

    def my_shape_cast(obj, *, src_loc_at=0):
        ... # additionally process `obj`...
        return Shape.cast(obj, src_loc_at=1 + src_loc_at)

The number `1` corresponds to the number of call stack frames that should be skipped.

## Shapes

See also the introduction to shapes and casting from shape-like objects in the language guide.

class amaranth.hdl.Shape(width=1, signed=False)

  Bit width and signedness of a `Value`.

  A `Shape` can be obtained by:

  - constructing with explicit bit width and signedness;

  - using the `signed()` and `unsigned()` aliases if the signedness is known upfront;

  - casting from a variety of objects using the `cast()` method.

  Parameters:

    - width (int) – The number of bits in the representation of a value. This includes the sign bit for signed values. Cannot be zero if the value is signed.

    - signed (bool) – Whether the value is signed. Signed values use the two’s complement representation.

  static cast(obj, *, src_loc_at=0)

    Cast `obj` to a shape.

    Many shape-like objects can be cast to a shape:

    - a `Shape`, where the result is itself;

    - an `int`, where the result is `unsigned(obj)`;

    - a `range`, where the result has minimal width required to represent all elements of the range, and is signed if any element of the range is signed;

    - an `enum.Enum` whose members are all constant-castable or `enum.IntEnum`, where the result is wide enough to represent any member of the enumeration, and is signed if any member of the enumeration is signed;

    - a `ShapeCastable` object, where the result is obtained by repeatedly calling `obj.as_shape()`.

    Raises:

      - TypeError – If `obj` cannot be converted to a `Shape`.

      - RecursionError – If `obj` is a `ShapeCastable` object that casts to itself.

  __repr__()

    Python code that creates this shape.

    Returns `f"signed({self.width})"` or `f"unsigned({self.width})"`.

amaranth.hdl.unsigned(width)

  Returns `Shape(width, signed=False)`.

amaranth.hdl.signed(width)

  Returns `Shape(width, signed=True)`.

class amaranth.hdl.ShapeCastable

  Interface class for objects that can be cast to a `Shape`.

  Shapes of values in the Amaranth language are specified using shape-like objects. Inheriting a class from `ShapeCastable` and implementing all of the methods described below adds instances of that class to the list of shape-like objects recognized by the `Shape.cast()` method. This is a part of the mechanism for seamlessly extending the Amaranth language in third-party code.

  To illustrate their purpose, consider constructing a signal from a shape-castable object `shape_castable`:

      value_like = Signal(shape_castable, init=initializer)

  The code above is equivalent to:

      value_like = shape_castable(Signal(
          shape_castable.as_shape(),
          init=shape_castable.const(initializer)
      ))

  Note that the `shape_castable(x)` syntax performs `shape_castable.__call__(x)`.

  Tip

  The source code of the `amaranth.lib.data` module can be used as a reference for implementing a fully featured shape-castable object.

  as_shape()

    Convert `self` to a shape-like object.

    This method is called by the Amaranth language to convert `self` to a concrete `Shape`. It will usually return a `Shape` object, but it may also return another shape-like object to delegate its functionality.

    This method must be idempotent: when called twice on the same object, the result must be exactly the same.

    This method may also be called by code that is not a part of the Amaranth language.

    Return type:

      Any other object recognized by `Shape.cast()`.

    Raises:

      Exception – When the conversion cannot be done. This exception must be propagated by callers (except when checking whether an object is shape-castable or not), either directly or as a cause of another exception.

  const(obj)

    Convert a constant initializer `obj` to its value representation.

    This method is called by the Amaranth language to convert `obj`, which may be an arbitrary Python object, to a concrete value-like object. The object `obj` will usually be a Python literal that can conveniently represent a constant value whose shape is described by `self`. While not constrained here, the result will usually be an instance of the return type of `__call__()`.

    For any `obj`, the following condition must hold:

        Shape.cast(self) == Const.cast(self.const(obj)).shape()

    This method may also be called by code that is not a part of the Amaranth language.

    Return type:

      A value-like object that is constant-castable.

    Raises:

      Exception – When the conversion cannot be done. This exception must be propagated by callers, either directly or as a cause of another exception. While not constrained here, usually the exception class will be `TypeError` or `ValueError`.

  from_bits(raw)

    Lift a bit pattern to a higher-level representation.

    This method is called by the Amaranth language to lift `raw`, which is an `int`, to a higher-level representation, which may be any object accepted by `const()`. Most importantly, the simulator calls this method when the value of a shape-castable object is retrieved.

    For any valid bit pattern `raw`, the following condition must hold:

        Const.cast(self.const(self.from_bits(raw))).value == raw

    While `const()` will usually return an Amaranth value or a custom value-castable object that is convenient to use while constructing the design, this method will usually return a Python object that is convenient to use while simulating the design. While not constrained here, these objects should have the same type whenever feasible.

    This method may also be called by code that is not a part of the Amaranth language.

    Return type:

      unspecified type

    Raises:

      Exception – When the bit pattern isn’t valid. This exception must be propagated by callers, either directly or as a cause of another exception. While not constrained here, usually the exception class will be `ValueError`.

  __call__(obj)

    Lift a value-like object to a higher-level representation.

    This method is called by the Amaranth language to lift `obj`, which may be any value-like object whose shape equals `Shape.cast(self)`, to a higher-level representation, which may be any value-like object with the same shape. While not constrained here, usually a `ShapeCastable` implementation will be paired with a `ValueCastable` implementation, and this method will return an instance of the latter.

    If `obj` is not as described above, this interface does not constrain the behavior of this method. This may be used to implement another call-based protocol at the same time.

    For any compliant `obj`, the following condition must hold:

        Value.cast(self(obj)) == Value.cast(obj)

    This method may also be called by code that is not a part of the Amaranth language.

    Return type:

      A value-like object.

  format(obj, spec)

    Format a value.

    This method is called by the Amaranth language to implement formatting for custom shapes. Whenever `"{obj:spec}"` is encountered by `Format`, and `obj` has a custom shape that has a `format()` method, `obj.shape().format(obj, "spec")` is called, and the format specifier is replaced with the result.

    The default `format()` implementation is:

        def format(self, obj, spec):
            return Format(f"{{:{spec}}}", Value.cast(obj))

    Return type:

      `Format`

class amaranth.hdl.ShapeLike

  Abstract class representing all objects that can be cast to a `Shape`.

  `issubclass(cls, ShapeLike)` returns `True` for:

  - `Shape`;

  - `ShapeCastable` and its subclasses;

  - `int` and its subclasses;

  - `range` and its subclasses;

  - `enum.EnumMeta` and its subclasses;

  - `ShapeLike` itself.

  `isinstance(obj, ShapeLike)` returns `True` for:

  - `Shape` instances;

  - `ShapeCastable` instances;

  - non-negative `int` values;

  - `range` instances;

  - `enum.Enum` subclasses where all values are value-like objects.

  This class cannot be instantiated or subclassed. It can only be used for checking types of objects.

## Values

See also the introduction to values and casting from value-like objects in the language guide.

class amaranth.hdl.Value(*, src_loc_at=0)

  Abstract representation of a bit pattern computed in a circuit.

  The Amaranth language gives Python code the ability to create a circuit netlist by manipulating objects representing the computations within that circuit. The `Value` class represents the bit pattern of a constant, or of a circuit input or output, or within a storage element; or the result of an arithmetic, logical, or bit container operation.

  Operations on this class interpret this bit pattern either as an integer, which can be signed or unsigned depending on the value’s `shape()`, or as a bit container. In either case, the semantics of operations that implement Python’s syntax, like `+` (also known as `__add__()`), are identical to the corresponding operation on a Python `int` (or on a Python sequence container). The bitwise inversion `~` (also known as `__invert__()`) is the sole exception to this rule.

  Data that is not conveniently representable by a single integer or a bit container can be represented by wrapping a `Value` in a `ValueCastable` subclass that provides domain-specific operations. It is possible to extend Amaranth in third-party code using value-castable objects, and the Amaranth standard library provides several built-in ones:

  - `amaranth.lib.enum` classes are a drop-in replacement for the standard Python `enum` classes that can be defined with an Amaranth shape;

  - `amaranth.lib.data` classes allow defining complex data structures such as structures and unions.

  Operations on `Value` instances return another `Value` instance. Unless the exact type and value of the result is explicitly specified below, it should be considered opaque, and may change without notice between Amaranth releases as long as the semantics remains the same.

  Note

  In each of the descriptions below, you will see a line similar to:

  Return type: `Value`, `unsigned(1)`, assignable

  The first part (`Value`) indicates that the returned object’s type is a subclass of `Value`. The second part (`unsigned(1)`) describes the shape of that value. The third part, if present, indicates that the value is assignable if `self` is assignable.

  static cast(obj)

    Cast `obj` to an Amaranth value.

    Many value-like objects can be cast to a value:

    - a `Value` instance, where the result is itself;

    - a `bool` or `int` instance, where the result is `Const(obj)`;

    - an `enum.IntEnum` instance, or a `enum.Enum` instance whose members are all integers, where the result is a `Const(obj, enum_shape)` where `enum_shape` is a shape that can represent every member of the enumeration;

    - a `ValueCastable` instance, where the result is obtained by repeatedly calling `obj.as_value()`.

    Raises:

      - TypeError – If `obj` cannot be converted to a `Value`.

      - RecursionError – If `obj` is a `ValueCastable` object that casts to itself.

  abstract shape()

    Shape of `self`.

    Return type:

      shape-like object

  as_unsigned()

    Reinterpretation as an unsigned value.

    Return type:

      `Value`, `unsigned(len(self))`, assignable

  as_signed()

    Reinterpretation as a signed value.

    Return type:

      `Value`, `signed(len(self))`, assignable

    Raises:

      ValueError – If `len(self) == 0`.

  __bool__()

    Forbidden conversion to boolean.

    Python uses this operator for its built-in semantics, e.g. `if`, and requires it to return a `bool`. Since this is not possible for Amaranth values, this operator always raises an exception.

    Raises:

      TypeError – Always.

  bool()

    Conversion to boolean.

    Returns the same value as `any()`, but should be used where `self` is semantically a number.

    Return type:

      `Value`, `unsigned(1)`

  __pos__()

    Unary position, `+self`.

    Returns:

      `self`

    Return type:

      `Value`, `self.shape()`

  __neg__()

    Unary negation, `-self`.

    Return type:

      `Value`, `signed(len(self) + 1)`

  __add__(other)

    Addition, `self + other`.

    Returns:

      - `Value`, `unsigned(max(self.width(), other.width()) + 1)` – If both `self` and `other` are unsigned.

      - `Value`, `signed(max(self.width() + 1, other.width()) + 1)` – If `self` is unsigned and `other` is signed.

      - `Value`, `signed(max(self.width(), other.width() + 1) + 1)` – If `self` is signed and `other` is unsigned.

      - `Value`, `signed(max(self.width(), other.width()) + 1)` – If both `self` and `other` are unsigned.

  __radd__(other)

    Addition, `other + self` (reflected).

    Like `__add__()`, with operands swapped.

  __sub__(other)

    Subtraction, `self - other`.

    Returns:

      - `Value`, `signed(max(self.width(), other.width()) + 1)` – If both `self` and `other` are unsigned.

      - `Value`, `signed(max(self.width() + 1, other.width()) + 1)` – If `self` is unsigned and `other` is signed.

      - `Value`, `signed(max(self.width(), other.width() + 1) + 1)` – If `self` is signed and `other` is unsigned.

      - `Value`, `signed(max(self.width(), other.width()) + 1)` – If both `self` and `other` are unsigned.

    Return type:

      `Value`

  __rsub__(other)

    Subtraction, `other - self` (reflected).

    Like `__sub__()`, with operands swapped.

  __mul__(other)

    Multiplication, `self * other`.

    Returns:

      - `Value`, `unsigned(len(self) + len(other))` – If both `self` and `other` are unsigned.

      - `Value`, `signed(len(self) + len(other))` – If either `self` or `other` are signed.

  __rmul__(other)

    Multiplication, `other * self` (reflected).

    Like `__mul__()`, with operands swapped.

  __floordiv__(other)

    Flooring division, `self // other`.

    If `other` is zero, the result of this operation is zero.

    Returns:

      - `Value`, `unsigned(len(self))` – If both `self` and `other` are unsigned.

      - `Value`, `signed(len(self) + 1)` – If `self` is unsigned and `other` is signed.

      - `Value`, `signed(len(self))` – If `self` is signed and `other` is unsigned.

      - `Value`, `signed(len(self) + 1)` – If both `self` and `other` are signed.

  __rfloordiv__(other)

    Flooring division, `other // self` (reflected).

    If `self` is zero, the result of this operation is zero.

    Like `__floordiv__()`, with operands swapped.

  __mod__(other)

    Flooring modulo or remainder, `self % other`.

    If `other` is zero, the result of this operation is zero.

    Return type:

      `Value`, `other.shape()`

  __rmod__(other)

    Flooring modulo or remainder, `other % self` (reflected).

    Like `__mod__()`, with operands swapped.

  __eq__(other)

    Equality comparison, `self == other`.

    Return type:

      `Value`, `unsigned(1)`

  __ne__(other)

    Inequality comparison, `self != other`.

    Return type:

      `Value`, `unsigned(1)`

  __lt__(other)

    Less than comparison, `self < other`.

    Return type:

      `Value`, `unsigned(1)`

  __le__(other)

    Less than or equals comparison, `self <= other`.

    Return type:

      `Value`, `unsigned(1)`

  __gt__(other)

    Greater than comparison, `self > other`.

    Return type:

      `Value`, `unsigned(1)`

  __ge__(other)

    Greater than or equals comparison, `self >= other`.

    Return type:

      `Value`, `unsigned(1)`

  __abs__()

    Absolute value, `abs(self)`.

    Return type:

      `Value`, `unsigned(len(self))`

  __invert__()

    Bitwise NOT, `~self`.

    The shape of the result is the same as the shape of `self`, even for unsigned values.

    Warning

    In Python, `~0` equals `-1`. In Amaranth, `~C(0)` equals `C(1)`. This is the only case where an Amaranth operator deviates from the Python operator with the same name.

    This deviation is necessary because Python does not allow overriding the logical `and`, `or`, and `not` operators. Amaranth uses `&`, `|`, and `~` instead; if it wasn’t the case that `~C(0) == C(1)`, that would have been impossible.

    Return type:

      `Value`, `self.shape()`

  __and__(other)

    Bitwise AND, `self & other`.

    Returns:

      - `Value`, `unsigned(max(self.width(), other.width()))` – If both `self` and `other` are unsigned.

      - `Value`, `signed(max(self.width() + 1, other.width()))` – If `self` is unsigned and `other` is signed.

      - `Value`, `signed(max(self.width(), other.width() + 1))` – If `self` is signed and `other` is unsigned.

      - `Value`, `signed(max(self.width(), other.width()))` – If both `self` and `other` are unsigned.

  __rand__(other)

    Bitwise AND, `other & self`.

    Like `__and__()`, with operands swapped.

  all()

    Reduction AND; are all bits `1`?

    Return type:

      `Value`, `unsigned(1)`

  __or__(other)

    Bitwise OR, `self | other`.

    Returns:

      - `Value`, `unsigned(max(self.width(), other.width()))` – If both `self` and `other` are unsigned.

      - `Value`, `signed(max(self.width() + 1, other.width()))` – If `self` is unsigned and `other` is signed.

      - `Value`, `signed(max(self.width(), other.width() + 1))` – If `self` is signed and `other` is unsigned.

      - `Value`, `signed(max(self.width(), other.width()))` – If both `self` and `other` are unsigned.

  __ror__(other)

    Bitwise OR, `other | self`.

    Like `__or__()`, with operands swapped.

  any()

    Reduction OR; is any bit `1`?

    Performs the same operation as `bool()`, but should be used where `self` is semantically a bit sequence.

    Return type:

      `Value`, `unsigned(1)`

  __xor__(other)

    Bitwise XOR, `self ^ other`.

    Returns:

      - `Value`, `unsigned(max(self.width(), other.width()))` – If both `self` and `other` are unsigned.

      - `Value`, `signed(max(self.width() + 1, other.width()))` – If `self` is unsigned and `other` is signed.

      - `Value`, `signed(max(self.width(), other.width() + 1))` – If `self` is signed and `other` is unsigned.

      - `Value`, `signed(max(self.width(), other.width()))` – If both `self` and `other` are unsigned.

  __rxor__(other)

    Bitwise XOR, `other ^ self`.

    Like `__xor__()`, with operands swapped.

  xor()

    Reduction XOR; are an odd amount of bits `1`?

    Return type:

      `Value`, `unsigned(1)`

  __lshift__(other)

    Left shift by variable amount, `self << other`.

    Returns:

      - `Value`, `unsigned(len(self) + 2 ** len(other) - 1)` – If `self` is unsigned.

      - `Value`, `signed(len(self) + 2 ** len(other) - 1)` – If `self` is signed.

    Raises:

      TypeError – If `other` is signed.

  __rlshift__(other)

    Left shift by variable amount, `other << self`.

    Like `__lshift__()`, with operands swapped.

  shift_left(amount)

    Left shift by constant amount.

    If `amount < 0`, performs the same operation as `self.shift_right(-amount)`.

    Returns:

      - `Value`, `unsigned(max(len(self) + amount, 0))` – If `self` is unsigned.

      - `Value`, `signed(max(len(self) + amount, 1))` – If `self` is signed.

  rotate_left(amount)

    Left rotate by constant amount.

    If `amount < 0`, performs the same operation as `self.rotate_right(-amount)`.

    Return type:

      `Value`, `unsigned(len(self))`, assignable

  __rshift__(other)

    Right shift by variable amount, `self >> other`.

    Returns:

      - `Value`, `unsigned(len(self))` – If `self` is unsigned.

      - `Value`, `signed(len(self))` – If `self` is signed.

    Raises:

      TypeError – If `other` is signed.

  __rrshift__(other)

    Right shift by variable amount, `other >> self`.

    Like `__rshift__()`, with operands swapped.

  shift_right(amount)

    Right shift by constant amount.

    If `amount < 0`, performs the same operation as `self.shift_left(-amount)`.

    Returns:

      - `Value`, `unsigned(max(len(self) - amount, 0))` – If `self` is unsigned.

      - `Value`, `signed(max(len(self) - amount, 1))` – If `self` is signed.

  rotate_right(amount)

    Right rotate by constant amount.

    If `amount < 0`, performs the same operation as `self.rotate_left(-amount)`.

    Return type:

      `Value`, `unsigned(len(self))`, assignable

  __len__()

    Bit width of `self`.

    Returns:

      `self.shape().width`

    Return type:

      `int`

  __getitem__(key)

    Bit slicing.

    Selects a constant-width, constant-offset part of `self`. All three slicing syntaxes (`self[i]`, `self[i:j]`, and `self[i:j:k]`) as well as negative indices are supported. Like with other Python containers, out-of-bounds indices are trimmed to the bounds of `self`.

    To select a variable-offset part of `self`, use `bit_select()` or `word_select()` instead.

    Returns:

      - `Value`, `unsigned(1)`, assignable – If `key` is an `int`.

      - `Value`, `unsigned(j - i)`, assignable – If `key` is a slice `i:j` where `i` and `j` are `int`s.

      - `Value`, `unsigned(len(range(*slice(i, j, k).indices(len(self)))))`, assignable – If `key` is a slice `i:j:k` where `i`, `j`, and `k` are `int`s.

  __contains__(other)

    Forbidden membership test operator.

    Python requires this operator to return a `bool`. Since this is not possible for Amaranth values, this operator always raises an exception.

    To check membership in a set of constant integer values, use `matches()` instead.

    Raises:

      TypeError – Always.

  bit_select(offset, width)

    Part-select with bit granularity.

    Selects a constant width, variable offset part of `self`, where parts with successive offsets overlap by `width - 1` bits. Bits above the most significant bit of `self` may be selected; they are equal to zero if `self` is unsigned, to `self[-1]` if `self` is signed, and assigning to them does nothing.

    When `offset` is a constant integer and `offset + width <= len(self)`, this operation is equivalent to `self[offset:offset + width]`.

    Parameters:

      - offset (value-like) – Index of the first selected bit.

      - width (`int`) – Amount of bits to select.

    Return type:

      `Value`, `unsigned(width)`, assignable

    Raises:

      - TypeError – If `offset` is signed.

      - TypeError – If `width` is negative.

  word_select(offset, width)

    Part-select with word granularity.

    Selects a constant width, variable offset part of `self`, where parts with successive offsets are adjacent but do not overlap. Bits above the most significant bit of `self` may be selected; they are equal to zero if `self` is unsigned, to `self[-1]` if `self` is signed, and assigning to them does nothing.

    When `offset` is a constant integer and `width:(offset + 1) * width <= len(self)`, this operation is equivalent to `self[offset * width:(offset + 1) * width]`.

    Parameters:

      - offset (value-like) – Index of the first selected word.

      - width (`int`) – Amount of bits to select.

    Return type:

      `Value`, `unsigned(width)`, assignable

    Raises:

      - TypeError – If `offset` is signed.

      - TypeError – If `width` is negative.

  replicate(count)

    Replication.

    Equivalent to `Cat(self for _ in range(count))`, but not assignable.

    Return type:

      `Value`, `unsigned(len(self) * count)`

    Raises:

      TypeError – If `count` is negative.

  matches(*patterns)

    Pattern matching.

    Matches against a set of patterns, recognizing the same grammar as `with m.Case()`. The pattern syntax is described in the language guide.

    Each of the `patterns` may be a `str` or a constant-castable object.

    Return type:

      `Value`, `unsigned(1)`

    Raises:

      SyntaxError – If a pattern has invalid syntax.

  eq(value, *, src_loc_at=0)

    Assignment.

    Once it is placed in a domain, an assignment changes the bit pattern of `self` to equal `value`. If the bit width of `value` is less than that of `self`, it is zero-extended (for unsigned `value`s) or sign-extended (for signed `value`s). If the bit width of `value` is greater than that of `self`, it is truncated.

    Return type:

      `Statement`

  __hash__ = None

    Forbidden hashing.

    Python objects are hashable if they provide a `__hash__` method that returns an `int` and an `__eq__` method that returns a `bool`. Amaranth values define `__eq__()` to return a `Value`, which precludes them from being hashable.

    To use a `Value` as a key in a `dict`, use the following pattern:

        value = Signal()
        assoc = {}
        assoc[id(value)] = value, "a signal"
        _, info = assoc[id(value)]
        assert info == "a signal"

  __format__(format_desc)

    Forbidden formatting.

    Since normal Python formatting (f-strings and `str.format`) must immediately return a string, it is unsuitable for formatting Amaranth values. To format a value at simulation time, use `Format` instead. If you really want to dump the AST at elaboration time, use `repr` instead (for instance, via `f"{value!r}"`).

class amaranth.hdl.ValueCastable

  Interface class for objects that can be cast to a `Value`.

  Computations in the Amaranth language are described by combining value-like objects. Inheriting a class from `ValueCastable` and implementing all of the methods described below adds instances of that class to the list of value-like objects recognized by the `Value.cast()` method. This is a part of the mechanism for seamlessly extending the Amaranth language in third-party code.

  Note

  All methods and operators defined by the `Value` class will implicitly cast a `ValueCastable` object to a `Value`, with the exception of arithmetic operators, which will prefer calling a reflected arithmetic operation on the `ValueCastable` argument if it defines one.

  For example, if `value_castable` implements `__radd__`, then `C(1) + value_castable` will perform `value_castable.__radd__(C(1))`, and otherwise it will perform `C(1).__add__(value_castable.as_value())`.

  as_value()

    Convert `self` to a value-like object.

    This method is called by the Amaranth language to convert `self` to a concrete `Value`. It will usually return a `Value` object, but it may also return another value-like object to delegate its functionality.

    This method must be idempotent: when called twice on the same object, the result must be exactly the same.

    This method may also be called by code that is not a part of the Amaranth language.

    Return type:

      Any other object recognized by `Value.cast()`.

    Raises:

      Exception – When the conversion cannot be done. This exception must be propagated by callers, either directly or as a cause of another exception. It is recommended that, in cases where this method raises an exception, the `shape()` method also raises an exception.

  shape()

    Compute the shape of `self`.

    This method is not called by the Amaranth language itself; whenever it needs to discover the shape of a value-castable object, it calls `self.as_value().shape()`. However, that method must return a `Shape`, and `ValueCastable` subclasses may have a richer representation of their shape provided by an instance of a `ShapeCastable` subclass. This method may return such a representation.

    This method must be idempotent: when called twice on the same object, the result must be exactly the same.

    The following condition must hold:

        Shape.cast(self.shape()) == Value.cast(self).shape()

    Return type:

      A shape-like object.

    Raises:

      Exception – When the conversion cannot be done. This exception must be propagated by callers, either directly or as a cause of another exception. It is recommended that, in cases where this method raises an exception, the `as_value()` method also raises an exception.

class amaranth.hdl.ValueLike

  Abstract class representing all objects that can be cast to a `Value`.

  `issubclass(cls, ValueLike)` returns `True` for:

  - `Value`;

  - `ValueCastable` and its subclasses;

  - `int` and its subclasses (including `bool`);

  - `enum.Enum` subclasses where all values are value-like;

  - `ValueLike` itself.

  `isinstance(obj, ValueLike)` returns the same value as `issubclass(type(obj), ValueLike)`.

  This class cannot be instantiated or subclassed. It can only be used for checking types of objects.

  Note

  It is possible to define an enumeration with a member that is value-like but not constant-castable, meaning that `issubclass(BadEnum, ValueLike)` returns `True`, but `Value.cast(BadEnum.MEMBER)` raises an exception.

  The `amaranth.lib.enum` module prevents such enumerations from being defined when the shape is specified explicitly. Using `amaranth.lib.enum` and specifying the shape ensures that all of your enumeration members are constant-castable and fit in the provided shape.