Circular shift operation
See original GitHub issueCircular shift or bit rotation (https://en.wikipedia.org/wiki/Circular_shift) is common bit-wise operation in many applications including cryptography. VHDL offers operators ror
and rol
as well as more polished versions as functions rotate_left
and rotate_right
for signed and unsigned types.
While the user can implement it using bit slicing and concatenation, it could become a little tricky and prone to mistakes. It would be nice to have operators/methods for this in Chisel.
A possible implementation for static rotation is:
implicit class RotatableUInt(u: UInt) {
def <<<(x: Int): UInt =
if (x == 0)
u
else if (x > 0) {
val w = u.getWidth
u(w - x - 1, 0) ## u(w - 1, w - x)
}
else
this >>> (-x)
def >>>(x: Int): UInt =
if (x > 0) {
val w = u.getWidth
u(x - 1, 0) ## u(w - 1, x)
}
else
this <<< (-x)
Gotchas:
- Verilog and C don’t seem to have operators for this operation. Verilog is using
>>>
operator as sign extension shift.
Type of issue: feature request
Impact: API addition (no impact on existing code)
Development Phase: proposal
Other information
If the current behavior is a bug, please provide the steps to reproduce the problem:
What is the current behavior?
What is the expected behavior?
Please tell us about your environment:
What is the use case for changing the behavior?
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (5 by maintainers)
Top GitHub Comments
I’d avoid the names
<<<
and>>>
like the plague. Not only are they used for arithmetic shifts in Verilog, they’re used for logical shifts in Scala!rotateLeft
androtateRight
aren’t too long to type, and they’ll leave no one guessing.The static rotates can be defined without relying on getWidth, so they can work without knowing the width at elaboration time:
These will issue an error when the magnitude of n exceeds the width, which is an artificial limitation, but is probably OK in practice. For the special case that the width is known at elaboration time, we could reduce the argument with a modulus.
Supporting dynamic rotates is trickier because of argument reduction on the shift amount, given that we permit non-power-of-2-sized UInts. What does it mean to right-shift a 13-bit-wide UInt by 9711? The correct answer is, of course, that it should be equivalent to right-shifting it by (9711 % 13), or 0. But computing that requires an expensive arithmetic circuit. If you first truncate the rotate amount to 4 bits, you get a different result: (9711 % 16) % 13 is 2.
I would just recommend against defining dynamic rotates, or as a compromise, only define them for known-power-of-2-sized inputs, to save users from shooting themselves in the foot with either poor performance or surprising semantics.
I think we need to hear from some other chisel devs about expanding the API, but it would be nice if you prepared the PR (and tests).
I’m fine with not having the special argument-reduction case when the width is known, and I’m also fine with erroring in Firrtl if n is too big. Some other operators behave the same way.
Limiting this to UInt makes sense to me.