[stella] Newbie: Efficiency in Code, Joystick Routine as Example

Subject: [stella] Newbie: Efficiency in Code, Joystick Routine as Example
From: "Roagie" <roagie@xxxxxxx>
Date: Sun, 14 Jul 2002 11:56:07 -0700
For all us newbies, as I discover useful things I will share them here. I
encourage you all to the do same thing. Perhaps we should adopt a subject
tag so stella vets can filter out the newbie posts if so desired.
I will start these posts with "[stella] Newbie:"
BTW, how many newbies are actively reading this list anyway? in otherwords,
are there people here that will benefit from me sharing my findings?


I just had a revelation into one of assembly's greatest advantages. Through
analysis of this clever joystick algorithm, one can see that simple bit
manipulation offers great amounts of efficiency.

Here is a joystick read routine that is not so efficient, it follows the
standard programming technique one would use in something like C++ or basic:

 LDA SWCHA    ; read joystick register, load into accumulator.
              ; Note: $EF = up, $DF = down, $BF = left, $7F = right

 CMP #$EF    ; compare what's in A (accumulator) with $EF.
 BEQ up      ; if they are equal, then branch to 'up' routine

 CMP #$DF    ; etc
 BEQ down

 CMP #$BF    ; etc
 BEQ left

 CMP #$7F    ; etc
 BEQ right

So the above routine has to compare all those bits to determine the byte.
That's gotta be quite a few cycles chewed up.

Now look at this clever code that accomplishes the same thing:

        LDA  SWCHA
        BCC right ; only right (01111111b) will clear the carry when left
        BCC left  ; shift again, only left will clear the carry (C = 0)
        BCC down  ; shift again, only down will clear the carry
        BCC up   ; shift again, only up wil clear the carry
        RTS   ; otherwise, it's 255 (11111111b) and means stick is centered

This looks bizarre, don't it?
Here's how it works:
First we need to know how the values returned by SWCHA look in binary.
    $EF = 1110 1111    ;up
    $DF = 1101 1111    ;down
    $BF = 1011 1111    ;left
    $7F = 0111 1111    ;right

Notice the pattern? Now what the clever routine does is it loads the value
into the accumulator, and then shifts all the bits to the left with the ASL
command. When this happens the leftmost bit (bit 7) is moved out of the
accumulator and into the C register of the processor. Notice that if a 0 is
loaded into C, then that means it could only be one thing, that the value in
the accumulator before the shift was $7F (0111 1111). And since that is the
value for 'right', then the joystick was moved to the right.
This is checked by the BCC command executed right after the shift, which
branches only if C = 0.
Now if the stick was another value, then this check is passed over since a 1
would be in C after the first left shift. So what happens next is that the
bits are shifted left again, and notice that only one of the remaining three
possibilities has a leftmost 0 after the first shift. Thus if C = 0 on the
second BCC, then it can only be $BF.
This continues until all possibilities are exhausted and it's obvious that
the stick is centered (or held diagonal).

So the the main difference between the two routines is that the first one
has to compare a whole byte for each possibility, while the second routine
compares 1 bit. That's 8 times more efficient (I think). This also reveals
one of assemblies greatest tricks. manipulate those bits for quick compares
in the processor registers! You would begin this process by examining the
bit pattern of the candidates for comparison.

BTW, if you don't know about the processors registers, then read about them
in "Assembly In One Step": http://www.geocities.com/oneelkruns/asm1step.html
. They are your friend!

Please, if I have made any errors in my analysis, correct me!

Archives (includes files) at http://www.biglist.com/lists/stella/archives/
Unsub & more at http://www.biglist.com/lists/stella/

Current Thread