Description
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?