Page 6 of 7
Posted: Tue Mar 23, 2010 4:33 pm
by AndiNo
mic_ wrote:The loading code is pretty much self-contained in loadspc.asm. The only stuff you'd need from spcplay.asm is the call to LoadSPC, and the stuff at the bottom that INCBINs the .SPC file data.
I guess I can work with that. Thanks!
Currently both SPC uploaders seem to do the same for me (as an outsider). Is that so or is one better than the other?
If I understand that correctly there is no way to upload another SPC after the first is uploaded to the APU. How did the game developers do that? It has to work somehow I guess. IIRC there were games in which the music was stopped during the game, too. Would this be done by uploading an empty SPC file?
Posted: Tue Mar 23, 2010 5:13 pm
by tepples
AndiNo wrote:If I understand that correctly there is no way to upload another SPC after the first is uploaded to the APU. How did the game developers do that? It has to work somehow I guess.
Each SPC program can receive commands on the four input ports. One command might be "stop song"; another might be "start other song whose note pattern data is already loaded"; another might be "reset and prepare to load another SPC". But these commands differ from one player routine to another.
Posted: Wed Mar 24, 2010 1:40 am
by AndiNo
So that means you have to implement the behaviour yourself I guess... How would you go about doing this with a given SPC file? Would you need to change the SPC itself or would you just upload different data? Would I be able to see these commands in SPCs from commercial games for example?
Posted: Wed Mar 24, 2010 2:16 am
by mic_
Run the game in the debugger version of BSNES and set a breakpoint for reads from $F4 on the S-SMP bus (and possibly $F5, $F6, $F7). Then step through the code from there to see what it does with the values it reads from those ports.
Or you could run the entire .SPC (at least everything between offsets $00100 and $100FF) through an SPC700 disassembler and search for such reads in the resulting code if you think using a debugger is cumbersome. The problem with this is that the disassembler can't tell code from data so it may end up messing up the disassembly.
Posted: Wed Mar 24, 2010 4:31 pm
by AndiNo
AndiNo wrote:I guess I can work with that.
Well seems like I've hit a wall now. The SNES SDK uses a modified version of WLA 9.4 with which I can not create a ROM from your spc player source. I got it working only with the usual WLA 9.5 I found somewhere, however I can't use this version within the SDK because of strange errors when assembling/linking.
I somehow integrated parts of your source into my game though and tried calling the ASM "function" LoadSPC from C, although something went wrong because the game freezes when calling it. I'll have to investigate a bit further although currently I have no real idea what I'm doing

Is there a way to step through the LoadSPC function while my program executes it (maybe with the BSNES debugger or something)?
edit: The spcplay.asm was cut down to this: (sorry I couldn't get it smaller here)
Code: Select all
.include "snes.inc"
.define SPC_FILE "so-01.spc"
.include "loadspc.asm"
; SPC-700 register values
.bank 1 slot 0
.org $0000
.incbin SPC_FILE skip $00025 read $0008
; DSP register values
.org $4000
.incbin SPC_FILE skip $10100 read $0080
; The actual 64k SPC RAM dump
.bank 2
.section "musicDataLow"
.incbin SPC_FILE skip $0100 read $8000
.ends
.bank 3
.section "musicDataHigh"
.incbin SPC_FILE skip $8100 read $8000
.ends
Am I missing something important?
Posted: Thu Mar 25, 2010 2:52 am
by mic_
Is there a way to step through the LoadSPC function while my program executes it (maybe with the BSNES debugger or something)?
Use bsnes-debugger.exe. Open Tools->Debugger. Check the "Step S-CPU" box. Press Break. Press Step as many times as you like.
One thing that might help is if you could see the assembly that the C compiler generates from your C code. Like how it's actually calling the LoadSPC function.
Since I haven't used SNESC myself I don't know if it's possible to make it output an assembly file for you.
Posted: Thu Mar 25, 2010 6:23 am
by AndiNo
Nice

Thanks! I found out it hangs in an infinite loop in loadspc.asm here:
Code: Select all
.macro waitForAudio0M
sta spcMirrorVal
-: cmp REG_APUI00
bne -
.endm
As one can see in the debug output:
Code: Select all
0083f7 bne $83f4 [0083f4] A:01aa X:00f2 Y:0002 S:1fe0 D:0000 DB:7e NvMxdIzC V:241 H: 12
0083f4 cmp $2140 [7e2140] A:01aa X:00f2 Y:0002 S:1fe0 D:0000 DB:7e NvMxdIzC V:241 H: 34
0083f7 bne $83f4 [0083f4] A:01aa X:00f2 Y:0002 S:1fe0 D:0000 DB:7e NvMxdIzC V:241 H: 66
0083f4 cmp $2140 [7e2140] A:01aa X:00f2 Y:0002 S:1fe0 D:0000 DB:7e NvMxdIzC V:241 H: 88
...
What does this tell me and is there something I can do about it? At least it looks like the ASM code is called correctly. I found out the SNESC compiler does not allow inline ASM for the 65816 target...
Is there a way in BSNES to see the log of the running program without clicking STEP a thousand times? Other than that it's pretty helpful
And yes the compiler itself only creates ASM files so I can see my program in assembly.
edit:
I used Geigers debugger to get what I wanted. I've reduced my code to a minimum to find the error. Here's my current code:
http://pastebin.com/TcHKqG2i
And here's the log from shortly before it hangs. Can anybody see what happened before it hangs? My assembly knowledge doesn't seem to suffice
http://pastebin.com/8M4zu3DL
Posted: Thu Mar 25, 2010 7:04 am
by mic_
Code: Select all
0083f7 bne $83f4 [0083f4] A:01aa X:00f2 Y:0002 S:1fe0 D:0000 DB:7e NvMxdIzC V:241 H: 12
0083f4 cmp $2140 [7e2140] A:01aa X:00f2 Y:0002 S:1fe0 D:0000 DB:7e NvMxdIzC V:241 H: 34
It tells me that the SPC is not responding when the CPU is trying to send data to it. This would happen if the SPC already was executing some code other than the IPL ROM - e.g. if you've already called LoadSPC once and then tried calling it again.
Is there a way in BSNES to see the log of the running program without clicking STEP a thousand times? Other than that it's pretty helpful
Yes. Check the "Trace S-CPU opcodes" box in the debugger window. You'll get a large file in the BSNES directory that lists all the instructions that were executed.
Posted: Thu Mar 25, 2010 7:19 am
by AndiNo
Thanks for your continuing help!
I've edited the above post with some more information. I've also uploaded the complete log of my program here:
http://www.file-upload.net/download-237 ... g.zip.html
Posted: Thu Mar 25, 2010 7:21 am
by mic_
It looks as if an interrupt was serviced during the SPC uploading procedure. Interrupts must be disabled while sending data to the SPC, and in fact disabling them is the first thing I do in LoadSPC. I'm not sure how that still managed to happen in your program.
Posted: Thu Mar 25, 2010 7:34 am
by mic_
Ok, the last log doesn't have that interrupt weirdness. What's happening here is that the C compiler is messing with DBR and the status register.
Remove the first 3 instructions in LoadSPC (stz/sei/sta) and replace them with this code:
Code: Select all
php
phb
sep #$20
stz REG_NMI_TIMEN
sei
stz spcSongNr
lda #0
pha
plb
And right before the RTS-instruction at the end of the LoadSPC function, insert these instructions:
Posted: Thu Mar 25, 2010 8:33 am
by AndiNo
That weirdness could have come from the fact that I used frame advance to jump over all "normal" code.
Although I have no clue what they do your changes had some effect. The log has grown a lot but loops in another place with this code as it seems:
http://pastebin.com/qJw8iYpr
I had to cut the log as it was already over 100MB. I hope you can still spot the problem...
http://www.file-upload.net/download-237 ... e.zip.html
Posted: Thu Mar 25, 2010 8:43 am
by mic_
That's probably just the while-loop at the end of your main().
Posted: Thu Mar 25, 2010 9:13 am
by AndiNo
It would be kind of embarassing if that was true, however I can't hear any music playing after the upload. So there has to be something wrong don't you think? Are there any other things I have to change, maybe set values to special registers etc that are missing from my initialization code?
edit:
When I start my program in BSNES I can hear some very faint crackling shortly after the start. The "Flag - Echo Disable" does also change from true to false in the debugger properties viewer. So at least something is happening

edit2: When calling LoadSPC from my (non-trivial) game before the while loop the game freezes. The while-loop is never entered...
Posted: Thu Mar 25, 2010 9:41 am
by mic_
Well, I think that the stuff at the end of your trace is actually the while-loop in your main(), but I can't say for sure.
Anyway, the fact that you don't hear any music could mean e.g. that you're uploading the wrong data to the SPC. My loading code relies on a LOROM configuration, with the .SPC data being located in banks 1, 2 and 3 (this could be changed by altering SPC_DATA_BANK and SPC_REG_ADDR in loadspc.asm). Take a look at your .SMC file in a hex editor and make sure that the data starting at offset 0x10000 in the .SMC matches the data starting at offset 0x100 in the .SPC file. And the data at 0xC000 in the .SMC should match the data at 0x10100 in the .SPC.
You can also use the memory editor in BSNES' debugger to look at the S-APU RAM to see if the correct data has been uploaded to it.