News:

11 March 2016 - Forum Rules

Main Menu

(Solved) (SNES) Help with an ASM jump crashing the game

Started by Autumn Shinespark, October 17, 2020, 11:27:00 AM

Previous topic - Next topic

Autumn Shinespark

Background:
I'm adding custom code to my mod Arcana SOR, so the status screens are more informative. Most of it is rearranging things, but to add extra data I need ASM to read from a new location and store it in the dialogue buffer 1580-16F2. Before and after:



The bottom right column of numbers (ACDM) will be Attack-Critical-Defense-Magic Defense once I add font characters like a sword and shield. Right now I'm trying to pull the weapon's critical hit power with $80/C6DC, store it to the display buffer at $16F1, then call it when drawing the dialogue box. Decided to see if it worked before adding the magic defense as well. (Good thing I checked, because it doesn't work!)


Original code:

$87/A39D A6 00       LDX $00    [$00:1E00]   A:0000 X:0000 Y:0032 D:1E00 DB:80 S:1FF1 P:envmxdIZc HC:0536 VC:260 FC:31 I:00
$87/A39F A0 33 00    LDY #$0033              A:0000 X:06B5 Y:0032 D:1E00 DB:80 S:1FF1 P:envmxdIzc HC:0610 VC:260 FC:31 I:00
(Draws the ring text to display buffer)
$87/A3A2 20 C9 A3    JSR $A3C9  [$87:A3C9]   A:0000 X:06B5 Y:0033 D:1E00 DB:80 S:1FF1 P:envmxdIzc HC:0634 VC:260 FC:31 I:00

$87/A3A5 FA          PLX                     A:0000 X:06C5 Y:0043 D:1E00 DB:80 S:1FF1 P:envmxdIZC HC:1074 VC:000 FC:31 I:00
(Checks if current party member is a Spirit (value=2)
$87/A3A6 BD C3 11    LDA $11C3,x[$80:11C3]   A:0000 X:0000 Y:0043 D:1E00 DB:80 S:1FF3 P:envmxdIZC HC:1188 VC:000 FC:31 I:00
$87/A3A9 29 FF 00    AND #$00FF              A:0000 X:0000 Y:0043 D:1E00 DB:80 S:1FF3 P:envmxdIZC HC:1234 VC:000 FC:31 I:00
$87/A3AC C9 02 00    CMP #$0002              A:0000 X:0000 Y:0043 D:1E00 DB:80 S:1FF3 P:envmxdIZC HC:1258 VC:000 FC:31 I:00
$87/A3AF F0 11       BEQ $11    [$A3C2]      A:0000 X:0000 Y:0043 D:1E00 DB:80 S:1FF3 P:eNvmxdIzc HC:1282 VC:000 FC:31 I:00
$87/A3B1 DA          PHX                     A:0000 X:0000 Y:0043 D:1E00 DB:80 S:1FF3 P:eNvmxdIzc HC:1300 VC:000 FC:31 I:00
(Calculates Attack power)
$87/A3B2 22 CA C4 80 JSL $80C4CA[$80:C4CA]   A:0000 X:0000 Y:0043 D:1E00 DB:80 S:1FF1 P:eNvmxdIzc HC:1334 VC:000 FC:31 I:00


So I decided to splice it at 87/A3A5 (3A3A5)
22 30 E0 80 jsl 80E030
5A phy
DA phx
A2 00 00 ldx 0000
A0 00 00 ldy 0000
20 DC C6 jsr c6dc
09 00 20 ora #2000
8D F1 16 sta 16F1
FA plx
7A ply
FA plx
A2 00 00 ldx 0000
BD C3 11 lda 11c3,x
6B rtl


I made sure to match my pulls and pushes, but I was getting the wrong item off the stack (either the return pointer or another large number) so I just loaded zero afterwards for troubleshooting. Calling PLX PLY PLX seems to pull the return pointer, so I was playing around with skipping that last pull at $A3A5... but then after finishing that code it returned wrong! I get the feeling I'm mixing up my JSLs and RTLs somehow. I can provide more context on request. The critical hit code is at $80/C6DC, so I do have to jump from $87 somewhere. How do I know what kind of jump to use?
If you need me, I'll be over-analyzing how games work... instead of playing them.

abw

The way JSR/JSL/BRK work is by pushing their return address on to the stack to be used by a later RTS/RTL/RTI, so your second PLX is pulling one byte of the return address and the RTL is using the other bytes of the return address along with the value you were expecting that second PLX to pull, which is indeed almost guaranteed to produce unwanted behaviour such as crashes.

Assuming 87/A3A6 and 87/A3A9 are only reachable immediately after 87/A3A5 and your new code starts at 80/E030, splicing at 87/A3A6 should work much better:

; at 87/A3A6:
22 30 E0 80 jsl $80E030
; preserve original code alignment
EA nop
EA nop
; at 80/E030:
5A phy
DA phx
A2 00 00 ldx $0000
A0 00 00 ldy $0000
20 DC C6 jsr $c6dc
09 00 20 ora #$2000
8D F1 16 sta $16F1
FA plx
7A ply
BD C3 11 lda $11c3,x
29 FF 00 and #$00ff
6B rtl

Autumn Shinespark

Ohhh, the return address is 2 bytes. That makes sense.
I fixed it with your help, now working on a display logic error. Thanks!
If you need me, I'll be over-analyzing how games work... instead of playing them.

abw

Quote from: Sarah Shinespark on October 17, 2020, 05:04:45 PM
Ohhh, the return address is 2 bytes. That makes sense.
Only some of the time. The return address pushed by a JSR or BRK in 6502 mode is 2 bytes long, but a JSL or BRK in 65816 mode push a 3-byte return address. BRK also pushes an extra byte for a total of 3 bytes in 6502 mode or 4 bytes in 65816 mode.

Quote from: Sarah Shinespark on October 17, 2020, 05:04:45 PM
I fixed it with your help, now working on a display logic error. Thanks!
You're welcome!

Autumn Shinespark

I usually just see BRK in the middle of display code to indicate the end, so it's not obvious to me where it's going. So it uses the stack, huh?

And I got it working, had to add a JSR/RTL to call a function in another bank that ended with RTS, to get the currently selected character. The "C" in the bottom right is the weapon's critical hit rate (out of 255) and previously unviewable! Now to do magic defense.

If you need me, I'll be over-analyzing how games work... instead of playing them.

abw

Quote from: Sarah Shinespark on October 17, 2020, 10:49:38 PM
I usually just see BRK in the middle of display code to indicate the end, so it's not obvious to me where it's going. So it uses the stack, huh?
Software BRK jumps to the address specified by the interrupt vector, just like hardware IRQ does. The interrupt vector is located at $FFFE-$FFFF in 6502 mode or $00FFE6-$00FFE7 in 65816 mode. What the game does after following the reset vector is, of course, up to the game ;).

If you're going to be doing more ASM work, you might want to pick up a decent 65816 reference; I can recommend Programming the 65816, which covers all of this and much more!

Autumn Shinespark

Thanks, I'll keep it handy! I've mostly been using this guide to Ctrl-F the hex codes for commands, since I prefer writing them myself than learning xkas.
Got magic defense working too, now just working on some new graphics before splicing more functions in.
If you need me, I'll be over-analyzing how games work... instead of playing them.


Autumn Shinespark

That's a good explanation.
I get how the stack works, I just have trouble remembering which SEP/REP makes it 8 bit and which makes it 16 bit. Also only figured out recently that PHX etc pulls "a value" off the stack and not exclusively the last X value pushed  :D
If you need me, I'll be over-analyzing how games work... instead of playing them.

90s comeback

The Snes needs a second basic like program, Snes fans are way behind Sega genesis ones.