The SuperH-3, part 8: Bit shifting
The bit shifting operations are fairly straightforward.
; arithmetic (signed) shifts SHAL Rn ; Rn <<= 1, T = the bit shifted out SHAR Rn ; Rn >>= 1, T = the bit shifted out ; logical (unsigned) shifts SHLL Rn ; Rn <<= 1, T = the bit shifted out SHLR Rn ; Rn >>= 1, T = the bit shifted out SHLL2 Rn ; Rn <<= 2 SHLR2 Rn ; Rn >>= 2 SHLL8 Rn ; Rn <<= 8 SHLR8 Rn ; Rn >>= 8 SHLL16 Rn ; Rn <<= 16 SHLR16 Rn ; Rn >>= 16
You cannot shift by arbitrary constant amounts. Only certain fixed values are permitted. If you want to shift left by, say, 9, you’ll have to construct it from a SHLL8
and a SHLL
.
Note also that SHAL
and SHLL
are functionally equivalent. But they have different encodings, so the designers burned an opcode for a redundant operation.
There are no “large shift” options for right shifts. You can perform multiple one-bit shifts, or use a variable shift:
SHAD Rm, Rn ; if Rm > 0: Rn <<= (31 & Rm) ; if Rm = 0: nop ; if Rm < 0: Rn >>= (31 & -Rm), signed SHLD Rm, Rn ; if Rm > 0: Rn <<= (31 & Rm) ; if Rm = 0: nop ; if Rm < 0: Rn >>= (31 & -Rm), unsigned
Note that these shift instructions shift both left and right, depending on the sign of the shift amount. If you want to shift right by an amount in a register, you therefore need to negate the value, and then shift left.
Finally, we have rotation.
ROTL Rn ; rotate left, T contains carried-out bit ROTR Rn ; rotate right, T contains carried-out bit ROTCL Rn ; 33-bit rotate through T ROTCR Rn ; 33-bit rotate through T
The rotation instructions rotate either a 32-bit or 33-bit value by one position. For the 32-bit rotations, the bit that rotated off the end is copied to T. For the 33-bit rotations, the T flag acts as the 33rd bit.
We saw earlier that there is no NEGV
instruction. To detect overflow from a negation, you just have to check for the value 0x80000000
directly. Here’s the shortest sequence I could come up with:
; branch if Rn equals 0x80000000 rotl Rn ; rotate left one bit dt Rn ; decrement and test for zero bt underflow ; Y: underflow occurred
The result of the DT
is zero if the previous value was 1, and the previous value was 1 if the original value was 0x80000000
.
This is a destructive operation, so do it in a scratch register. You should have one available, since it’s the source register for the NEGV
you were checking.
We’ll look more at constants next time.
2 comments
“There are no “large shift” options for right shifts.”
Can you elaborate? The available operations for left and right shifts look totally symmetrical to me, so I must have misunderstood what is meant here.
On another note, seeing another dive into a to me unfamiliar architecture is very exciting. I was fearing that we ran out of qualifying architectures already. (As far as I remember, you only cover architectures for which a version of Windows existed?)
Derp. I’m not sure what I was thinking when I wrote that.