PBasic left shift of a byte quantity and sign bit manipulation.
Martin_H
Posts: 4,051
I was reading through some of Phil Pilgrims PBasic code and noticed something interesting. Here's a code snippet.
At first I was confused by shifting a byte eight places left. But then I realized it makes sense if Arg << 8 copies Arg into a 16 bit wide working register, then shift the working register left eight places. That way it can be added to the top byte of the Word DirErr. In the second line this is used to move Arg's sign bit into the top bit, take an absolute value, then shift it back to a byte. This is really compact and clever, because in similar circumstances I've been sign extending via the a test of the sign bit coupled with an OR before calling the ABS function on the extended quantity. I think my PBasic skills just jumped a notch as this bit shifting approach is much more compact.
The use of working registers is obvious when you look at a C compiler's assembler output, but less obvious with PBasic as it is compiled to byte codes. If there was a byte code pretty printer I bet more tricks like this would jump out at me.
' Note that Arg is defined as a Byte, while DirErr is a Word. Arg VAR Byte 'Requested travel or turn amount. DirErr VAR Word 'Current directional error in brads and 1/256 brads. ' Bunch of code removed. ' Here's an interesting line of code. DirErr = DirErr + (Arg << 8) 'Adjust direction error by amount of turn. ' A bit later this is even more interesting. Arg = ABS(Arg << 8) >> 8 'Amount of turn is absolute value of Arg.
At first I was confused by shifting a byte eight places left. But then I realized it makes sense if Arg << 8 copies Arg into a 16 bit wide working register, then shift the working register left eight places. That way it can be added to the top byte of the Word DirErr. In the second line this is used to move Arg's sign bit into the top bit, take an absolute value, then shift it back to a byte. This is really compact and clever, because in similar circumstances I've been sign extending via the a test of the sign bit coupled with an OR before calling the ABS function on the extended quantity. I think my PBasic skills just jumped a notch as this bit shifting approach is much more compact.
The use of working registers is obvious when you look at a C compiler's assembler output, but less obvious with PBasic as it is compiled to byte codes. If there was a byte code pretty printer I bet more tricks like this would jump out at me.
Comments
Arg = ABS(Arg << 8) >> 8
the math on Arg is done in a 16 bit working register, but in the end the low 8 bits of the working register are written back into Arg, a byte.
There are usually several ways to achieve a result. For example,
Arg = ABS(Arg << 8) >> 8
has the effect of zeroing bit7 of Arg. That might also be done, I think, as,
Arg.bit7 = 0
or
Arg = Arg & $3F
Tracy, don't forget that its doing more than clearing the sign bit. ABS is also undoing the two's complement. For example -1 = 0xFF in two's complement stored in one byte. I'd have 0x7F if I cleared bit 7, but 1 when I undo the two's complement.
Arg VAR byte
Arg = -Arg.bit7 ^ Arg + Arg.bit7
However, Phil's
Arg = ABS(Arg << 8) >> 8
is shorter in eeprom. The stamp code to address an individual bit takes more space than the code to address a byte.