Shop OBEX P1 Docs P2 Docs Learn Events
PBasic left shift of a byte quantity and sign bit manipulation. — Parallax Forums

PBasic left shift of a byte quantity and sign bit manipulation.

Martin_HMartin_H Posts: 4,051
edited 2012-09-07 12:08 in BASIC Stamp
I was reading through some of Phil Pilgrim’s PBasic code and noticed something interesting. Here's a code snippet.
' 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

  • Tracy AllenTracy Allen Posts: 6,662
    edited 2012-09-07 09:51
    Yes, variables on the right hand side of the equals sign are transferred into 16 bit working registers, even if the variable itself is only a single bit. That single bit will be bit0 in the 16 bit working register. At the end, the result may be truncated back down to the lower bits of the 16 bit argument. As in
    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
  • Martin_HMartin_H Posts: 4,051
    edited 2012-09-07 10:02
    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.
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2012-09-07 11:24
    You're ABSolutely right. I should know better than to second guess Phil, especially before a second cup of joe!
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2012-09-07 12:08
    A correct alternative is,
    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.
Sign In or Register to comment.