I'm new to assembly and trying to piece together what this piece of code is doing. Here's the Super NES 65c816 reference I'm using.
01: $A4917E AD E5 05 LDA $05E5 [$A4:05E5]
02: $A49181 29 3F 00 AND #$003F
03: $A49184 AA TAX
04: $A49185 AD E5 05 LDA $05E5 [$A4:05E5]
05: $A49188 89 02 00 BIT #$0002
06: $A4918B D0 05 BNE $05 [$9192]
07: $A4918D 8A TXA
08: $A4918E 49 FF FF EOR #$FFFF
09: $A49191 AA TAX
10: $A49192 8A TXA
11: $A49193 18 CLC
12: $A49194 6D 7A 0F ADC $0F7A [$A4:0F7A]
13: $A49197 85 12 STA $12 [$00:0012]
14: $A49199 AD E5 05 LDA $05E5 [$A4:05E5]
15: $A4919C 29 00 1F AND #$1F00
16: $A4919F EB XBA
17: $A491A0 85 14 STA $14 [$00:0014]
What I know already is that $05E5 is the storage location of the game's random number generator (RNG). It's a 16-bit value. What I'm trying to figure out is what kind of math the game's trying to do with this random number.
Here's a more trivial example, for starters:
$86AE1C AD E5 05 LDA $05E5 [$86:05E5]
$86AE1F 29 01 00 AND #$0001
$86AE22 F0 05 BEQ $05 [$AE29]
Here it's clearly just using the random number for a coin flip—the highest entropy bit being 0 or 1—to decide to branch or not.
Getting back to the original example, let me say what (I think) I understand, in pieces:
01: $A4917E AD E5 05 LDA $05E5 [$A4:05E5]
02: $A49181 29 3F 00 AND #$003F
03: $A49184 AA TAX
This is loading the random number into the accumulator, say 11010101001100010
, and AND'ing it to 0000000000111111
, yielding 0000000000100010
in the accumulator, which it then transfers to register X.
04: $A49185 AD E5 05 LDA $05E5 [$A4:05E5]
Next it loads the same random number into the accumulator—I guess because we lost it during the AND operation? (The random number is generated elsewhere, executing once approximately every 1/60th of a second. But it's guaranteed to be the same here.)
05: $A49188 89 02 00 BIT #$0002
06: $A4918B D0 05 BNE $05 [$9192]
Here's where it gets fuzzy for me. I read multiple resources online (though not specific to the 65816) saying BIT is like an AND but without mutating either operand. But it seems like there are some nuances having to do with flags.
Continuing with my example, am I correct to believe that
BIT #$0002
on the accumulator value of11010101001100010
would be 1, because the second lowest bit is 1?Am I correct to believe that as a result of the bit test, the z flag's value will have been set to 0, precisely the opposite of the previous result?
Am I correct to believe that it will then branch (to instructions at address $05), since Z=0?
Okay, if I've gotten those fundamentals down, then these are my real questions:
Why wouldn't the developers (who in those days optimized everything) have swapped lines 01-03 with 04-06? That is, if there's a chance you'll end up jumping to some totally different piece of code, why not test and do the jumping first, and only if not branching, do the AND operation? (Wait, is it possible register X might be used wherever the code jumps to?)
Could someone help me understand the next few instructions? In particular, what is the point of executing TAX then TXA? Isn't that just swapping then unswapping values?
Sorry this is many questions in one, but hopefully it's okay because I'm referring to the same set of instructions. Thanks in advance for any assistance.
P.S. Here's the page about BIT in a textbook I have about the 65816, in case it helps.
I could not understand the paragraph starting, "BIT is usually used immediately preceding a conditional branch instruction:", though it seems relevant...
Answering one of the questions about these lines
It is because of the branch at line 6, which if taken will execute from line 10.
The
TAX
shown is matching the previousTXA
(not the following one) as inSome whitespace or labels in the code would make this "phrasing" clearer, although the branch does give the destination address.
Questions 1-3 about the
Z
flag: you are correct in saying that theZ
flag is set if the result being tested is0
.Yes, but the
$05
is not an address, it is a signed displacement (from the instruction that would have followed, because thePC
program counter (akaIP
instruction pointer) would already have been advanced by the time the decision is taken).