Skip to content

[RFC] Add a (more) general shape conversion operator #381

Closed
@whitequark

Description

@whitequark

In response to #292 we've added operators that reinterpret a value of any signedness as a signed or unsigned value of the same width. It would be nice to have an operator that changes the width of a value, too.

Current workaround: for truncation, use v[:new_width]; for extension, use a no-op bitwise operation, like v | C(0, new_width).

  • Downside: this code is confusing when it is encountered among a bunch of arithmetic operations.
  • Downside: this code is fragile because neither of these operations is guaranteed to return a value with width new_width.

The workaround seems unacceptable to me.

Proposal 1: add two new operators, v.trunc(new_width) for truncation and v.extend(new_width) for zero/sign extension depending on the signedness of v. The new operators would make it an error to truncate to a larger width, or extend to a smaller width than the width of v.

  • Upside: the new operators reliably return a value with requested width.
  • Upside: the new operators eliminate bugs caused by extension being used instead of truncation or vice versa
  • Downside: the new operators accept a width, not a shape, so there is no way to extend a value until it matches the width inferred for range or an enum.
  • Downside: two new operators with quite limited use

Proposal 2: like Proposal 1, but the operators accept a new_shape rather than new_width, enforcing the same preconditions. The signedness of the result matches the signedness of the shape.

  • Upside: the new operators reliably return a value with requested width.
  • Upside: the new operators eliminate bugs caused by extension being used instead of truncation or vice versa
  • Upside: the new operators are quite expressive, and as_unsigned/as_signed can be implemented in terms of either.
  • Downside: two new flexible operators but "either extend or truncate"--chiefly what happens in x.eq(y)--still isn't expressible and requires an intermediate wire

Proposal 3: add one new operator, v.as(new_shape) for truncation, zero/sign extension, and type conversion. The new operator would extend v if new_shape.width > len(v), truncate v if new_shape.width < len(v), and return a value with shape new_shape.

  • Upside: the new operator reliably returns a value with requested width.
  • Upside: one operator that can express every implicit shape conversion done by nMigen, including as_unsigned/as_signed.
  • Downside: the new operator can hide bugs caused by extension being used instead of truncation or vice versa

Proposal 4: Proposals 2 and 3 at the same time

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions