It is currently Fri Aug 23, 2019 2:04 am

All times are UTC - 7 hours



Forum rules





Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Fri Aug 02, 2019 5:04 am 
Offline

Joined: Sat Aug 28, 2010 9:01 am
Posts: 228
I'm analyzing the Super Gameboy game Beach Volleyball because unlike most SGB games, it's using the SPC to play music. It's also interesting because it doesn't use the SGB command SOU_TRN to transfer the data. Instead it transfers code to the SNES which it calls to load the music. After the usual SGB hotpatch it transfers some more stuff to SNES RAM:
Code:
1 0F DATA_SND 79.00.18.00 0B.A9.01.8D 00.42.AF.DB FF.00.F0.05
1 0F DATA_SND 79.0B.18.00 0B.20.73.C5 80.03.20.76 C5.A9.31.8D
1 0F DATA_SND 79.16.18.00 03.00.42.60 00.00.00.00 00.00.00.00

This code doesn't appear in any other games.

Disassembled, the code looks like this:
Code:
0000:1800 A9 01        mov  a,01
0000:1802 8D 00 42     mov  [4200],a            ; Disable interrupts temporarily
0000:1805 AF DB FF 00  mov  a,[far 00FFDB]      ; Load SGB ROM version
0000:1809 F0 05        jz   1810
0000:180B 20 73 C5     call C573                ; Call if SGB v1
0000:180E 80 03        jr8  1813
0000:1810 20 76 C5     call C576                ; Call if SGB v0
0000:1813 A9 31        mov  a,31
0000:1815 8D 00 42     mov  [4200],a            ; Re-enable interrupts
0000:1818 60           ret

The code then calls a routine in the SGB BIOS whose location differs between the ROM revisions. This routine seems to load data from the SGB buffer and write it to the APU. Specifically, the display contents are hidden with the MASK_EN command as usual when doing a SGB transfer, then data is presented through VRAM and a JUMP command is executed to the location of the routine that was previously copied. Lastly the music is started using a SOUND command.

Code:
1 17 MASK_EN  B9.01.00.00 00.00.00.00 00.00.00.00 00.00.00.00
1 12 JUMP     91.00.18.00 00.00.00.00 00.00.00.00 00.00.00.00
1 12 JUMP     91.00.18.00 00.00.00.00 00.00.00.00 00.00.00.00
1 12 JUMP     91.00.18.00 00.00.00.00 00.00.00.00 00.00.00.00
1 08 SOUND    41.00.00.00 01.00.00.00 00.00.00.00 00.00.00.00


Before diving deeper into this, can anyone think of a reason why SOU_TRN would not be sufficient for transferring music data to the SPC?

_________________
Gameboy Genius (Blog) - Gameboy development forum (+wiki and file area)


Top
 Profile  
 
PostPosted: Fri Aug 02, 2019 5:32 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21560
Location: NE Indiana, USA (NTSC)
In more familiar syntax:
Code:
SGB_BIOS_VER = $FFDB
SGB0_apuload = $C576
SGB1_apuload = $C573

L1800:
  lda #$01
  sta $4200
  lda f:SGB_BIOS_VER
  beq is_SGB0
    jsr SGB1_apuload
    bra L1813
  is_SGB0:
    jsr SGB0_apuload
  L1813:
  lda #$1F
  sta $4200
  rts


At least the use of multiple JUMP commands like this shows that JUMP is more like a call than a plain jump, and so long as PBR is in bank 0, the program can return to SGB BIOS with RTS.

ISSOtm has been attempting a disassembly of SGB BIOS. He might be able to help suss out the identity of what I referred to above as SGB1_apuload.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Fri Aug 02, 2019 8:31 am 
Offline
User avatar

Joined: Fri Jan 04, 2019 5:31 pm
Posts: 39
Location: France, right of a pile of consoles
The mystery deepens. In the SGB1v1 and SGB1v2 BIOSes, the function at 80:C573 is... `ProcessSOU_TRN`.

Here is a slice of the SGB1v2 disassembly I'm making (note that SGB1v1 and SGB1v2 are almost identical, and most importantly aren't shifted)
Code:
.importzp FramebufferFarPtr ; $0098
.import PtrToFramebuffer ; $0284

.A8
ProcessSOU_TRN: ; 80C573
    LDA #$FF
    STA APUIO0 ; $2140
    JSR WaitFramebufferFilled ; 80C58D
    LDA PtrToFramebuffer
    STA FramebufferFarPtr
    LDA PtrToFramebuffer+1
    STA FramebufferFarPtr+1
    LDA #$7E
    STA FramebufferFarPtr+2
    JSR UploadAPUProgram
    RTS


This function is called by the SGB packet command dispatcher, so why they jump directly to the function instead of using the dedicated command, I don't understand.

I remembered something similar in the GB programming manual, but it stated the following:
Quote:
When using the SOU_TRN system command, send the following 5 packets of SOU_TRN default data to the register file before SOU_TRN is used.

Code:
DB $79, $00, $09, $00, $0B, $AD, $C2, $02, $C9, $09, $D0, $1A, $A9, $01, $8D, $00
DB $79, $0B, $09, $00, $0B, $42, $AF, $DB, $FF, $00, $F0, $05, $20, $73, $C5, $80
DB $79, $16, $09, $00, $0B, $03, $20, $76, $C5, $A9, $31, $8D, $00, $42, $68, $68
DB $79, $21, $09, $00, $01, $60, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
DB $79, $00, $08, $00, $03, $4C, $00, $09, $00, $00, $00, $00, $00, $00, $00, $00


_________________
The French Lord of Laziness (and a huge Legend of Zelda fan)
https://github.com/ISSOtm
ASMu is laifu <3


Top
 Profile  
 
PostPosted: Fri Aug 02, 2019 9:01 am 
Offline

Joined: Sat Aug 28, 2010 9:01 am
Posts: 228
The patch in Beach Volleyball is functionally the same as the SOU_TRN patch that exists in some ROMs. But instead of intercepting the command handler and checking if the command ID=SOU_TRN, it's implemented as a routine that you call with JUMP. Otherwise it does the exact same thing: disables H+V interrupts, calls either C576 or C573, restores interrupts and then returns. Why it's done this way instead of using the patch found in a bunch of other games is a mystery though. You'd have to check the chronology. Maybe this was the first game to include a patch for SOU_TRN and they hadn't figured out the other patch yet?

Why a patch is needed at all is likely because H+V IRQ interfered with the data transfer. I'm guessing the code that normally copies the incoming data to VRAM for example wrote to $6001 (Character Buffer Read Row Select) causing incorrect data to be read once the interrupt handler returned.
nocash wrote:
SOU_TRN Patch
this patch disables H+V IRQ during SOU_TRN, unknown when/why this is needed.
this patch is done by WHICH games? I haven't tried, but it should be easy to find such games using a hex editor with "find in multiple files" function, and then searching for the patch/packets.
Code:
                      ;------------------
0000:0800              jmp  0900 ;cmd_hook_cont
                      ;---
[...]                  [...]
                      ;---
                      cmd_hook_cont:
0000:0900 AD C2 02     mov  a,[02C2]  ;cmd      ;\
0000:0903 C9 09        cmp  a,09      ;SOU_TRN  ; check if SOU_TRN (cmd 09h)
0000:0905 D0 1A        jnz  0921 ;@@exit        ;/
0000:0907 A9 01        mov  a,01                ;\disable H+V IRQ
0000:0909 8D 00 42     mov  [4200],a            ;/
0000:090C AF DB FF 00  mov  a,[far 00FFDB]      ;\check ROM version
0000:0910 F0 05        jz   0917 ;@@version_0   ;/
0000:0912 20 73 C5     call C573 ;SOU_TRN_v1_v2 ;\
0000:0915 80 03        jr8  091A ;@@finish      ; execute SOU_TRN for SGBv0
                      @@version_0:              ; or SGBv1/SGBv2/SGB2v1
0000:0917 20 76 C5     call C576 ;SOU_TRN_v0    ;
                      @@finish:                 ;/
0000:091A A9 31        mov  a,31                ;\enable H+V IRQ
0000:091C 8D 00 42     mov  [4200],a            ;/
0000:091F 68           pop  a                   ;\flush retadr
0000:0920 68           pop  a                   ;/(cmd 09h already executed)
                      @@exit:
0000:0921 60           ret
                      ;------------------

_________________
Gameboy Genius (Blog) - Gameboy development forum (+wiki and file area)


Top
 Profile  
 
PostPosted: Fri Aug 02, 2019 9:54 am 
Offline

Joined: Sat Aug 28, 2010 9:01 am
Posts: 228
I tried changing the patches so they don't disable interrupts (writing $31 instead of $01 to $4200) and I couldn't hear or see any ill effects from it. I tried this in both Volleyball and Animaniacs with thei respective patches. I also tried running them in both PAL and NTSC, on a region modded PAL SNES. I only have a SGB1 to test on though. I might record audio from both versions and do a better A/B test though.

_________________
Gameboy Genius (Blog) - Gameboy development forum (+wiki and file area)


Top
 Profile  
 
PostPosted: Sat Aug 03, 2019 5:42 am 
Offline
User avatar

Joined: Fri Jan 04, 2019 5:31 pm
Posts: 39
Location: France, right of a pile of consoles
I have updated my WIP disassembly with the relevant functions, which are here. The `WaitFramebufferFilled` function is wrapped in interrupt-disabling code, I wonder if this is the case on SGB1v0 as well. (SGB1v2's sole modification from SGB1v1 is applying the OBJ_TRN patch at boot-up, so Nintendo did care about integrating the patches in the BIOS)

_________________
The French Lord of Laziness (and a huge Legend of Zelda fan)
https://github.com/ISSOtm
ASMu is laifu <3


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group