Page 3 of 7

Posted: Sat Feb 27, 2010 3:22 am
by mic_
Not all songs use echo, or at least doesn't have it enabled in their initial state (and thus no echo buffer start address specified). Sure, one could default to $ff70 for those songs.

Anyway, let's look at ff6-307.spc (from Final Fantasy 6), which is one song that requires you to press reset for it to start playing properly on a real SNES (there's no such problem in BSNES though). Every single byte from $f9a0..$ffff contains the value $ff, which doesn't seem to me like meaningful data. It uses an echo buffer ranging from $cd00..$f4ff, so there should be no risk of the echo buffer data overwriting the initialization code before it has finished executing. Still it behaves this way. The only difference I can see before and after pressing reset is that after pressing reset my code will start executing sooner, while on the first run I first have to make the flash cart copy the ROM to its internal RAM.

Posted: Sat Feb 27, 2010 4:07 am
by d4s
You got problems with random data corruption/crashes on the spc?
This is almost certainly caused by the echo buffer, as you already suggested.

I believe I disabled echo in my music player because I didn't want to waste any precious RAM, but I did try it once.

Absolutely make sure that you initialize the echo regs in the right order and with due delay between register writes! The latter is especially important.

Posted: Sat Feb 27, 2010 4:36 am
by mic_
How much delay is "due"? :) I mean, I'm verifying that the SPC echoes everything back with a cmp/bne loop.

I actually just tried moving the write to DSP reg $6c (FLG) away from the other DSP writes and down to my initialization routine. So now enabling echo is the last thing it does before it jumps to the PC init value. Still doesn't work properly.

Posted: Sat Feb 27, 2010 5:44 am
by mic_
My latest code: http://jiggawatt.org/badc0de/spcplayer-1.1.zip

I've managed to fix the problem with some songs occasionally not starting to play until you reset the system. At least I think I've fixed it, because I've not seen it happen a single time now, while it used to happen quite frequently with certain songs in the past.

The order in which you do things do certainly seem to be important. I've also tried to make sure that the echo feature is inactive before I upload anymore data to the SPC. As a result it will now take up to 2-3 seconds for some songs to start playing, but that's better than not playing at all. I may be using both a belt and suspenders here, but when I finally got it working I didn't feel like going back and see what I could remove.

EDIT: I noticed a flaw in my latest code: The jsr to CopySPCMemoryToRam should probably come after the code that writes $20 to FLG, in order to avoid overwriting the two bytes at $100..$101 in the SPC RAM dump. It seems to work anyway, so meh.. :P

Posted: Sat Feb 27, 2010 8:49 am
by blargg
When you power up the SPC, it often has a non-zero EDL. This means that the echo offset could become fairly large. So the first thing you want to do is set EDL to 0, and wait up to 1/4 second for the echo offset to become zero. Otherwise, even if you set EDL correctly, then enable echo in FLG, it could write way beyond what EDL would suggest because the echo offset won't have looped yet and used the new EDL.

I'm still trying to work out one last problem with my code. I think it may be due to not restoring the four I/O registers soon enough, so the SPC engine is interpreting them as commands from the game. I'm still getting occasional silence, even when echo is disabled in FLG. I was trying to run them in my SPC emulator, to trigger the problem there, but no go (I was running the upload code with a varying delay after resetting, in a loop).

Posted: Sat Feb 27, 2010 9:15 am
by mic_
Zeroing EDL wouldn't do much good in my case, since I still need to upload data to that area, so I can't have the DSP writing echo buffer data at all. That's why I disable echo in FLG before I start uploading data to the SPC or setting any other DSP regs, and then I enable echo again (if it should be enabled) right before I branch to the SPC entry point address.

Except for the occasional noise you might get at the start of a song my loader works perfectly, as you can see here: http://www.youtube.com/watch?v=ceIEKKJ-_70

Posted: Sat Feb 27, 2010 9:46 am
by bunnyboy
mic_ wrote: The order in which you do things do certainly seem to be important.
So future peoples don't have to dig through the source can you list what the important order parts are?

I started adding more of your ideas to my player and it has improved significantly. Should have another cleaned up beta mappers soon.

Posted: Sat Feb 27, 2010 10:03 am
by mic_
bunnyboy wrote:
mic_ wrote: The order in which you do things do certainly seem to be important.
So future peoples don't have to dig through the source can you list what the important order parts are?

I started adding more of your ideas to my player and it has improved significantly. Should have another cleaned up beta mappers soon.
Disable echo (FLG=$20) before sending anything else to the SPC.

Wait for EDL frames to make sure echo processing has stopped. I'm not sure if this is necessary when disabling echo altogether in FLG, but I do this anyway.

Initialize the DSP registers, except for FLG which should be initialized as late as possible.

Copy the SPC data to SPC RAM $0002..$00ef, $00f8..$00fc, $0100..$ffbf.

Copy your init routine to $ff70. Apart from initalizing the SPC registers, the init routine should init SPC RAM at $0000..$0001, IO regs $f0..$f1 and DSP register $6c. Most .SPC files contain $ff as the init value for IO reg $f0, but this seems to be a bad value to write to it. I write the value $0a.

Start execution on the SPC and as soon as the SNES side gets a $cc back from the SPC to indicate that execution is about to begin, initialize audio ports 0..3 on the SNES side with the data from $01f4..$01f7 in the .SPC file.

Posted: Sat Feb 27, 2010 10:04 am
by Bregalad
Great work _mic !
Hopefully it'll work with the super powerpak (that I just ordered).

Posted: Sat Feb 27, 2010 10:16 am
by bunnyboy
Is the "big red delay" at http://ekid.nintendev.com/snes/spctech.htm#dspedl what blargg was talking about, waiting 1/4 sec?

Posted: Sat Feb 27, 2010 10:30 am
by mic_
Most likely. It also mentions that you can wait EDL*16ms, which is what I do (or EDL*20ms since I have a PAL console).

Posted: Sat Feb 27, 2010 12:21 pm
by bunnyboy
I am probably missing something, but aren't you waiting based on the EDL value in the .spc instead of the value in the SPC700? Say the file says EDL is 1 but the chip has 100 already randomly loaded. Your wait won't be long enough?

Maybe it just isn't needed at all so it won't make a difference.

Posted: Sat Feb 27, 2010 12:26 pm
by Bregalad
EDL can only vary from 0 to 15. So if you wait enough time so that even if EDL was 15 it cycles trough the buffer once (I'm not sure how many time it is but about 1/2 a second) you're safe.

Posted: Sat Feb 27, 2010 1:07 pm
by blargg
mic_ wrote:Zeroing EDL wouldn't do much good in my case, since I still need to upload data to that area, so I can't have the DSP writing echo buffer data at all. That's why I disable echo in FLG before I start uploading data to the SPC or setting any other DSP regs, and then I enable echo again (if it should be enabled) right before I branch to the SPC entry point address.
Doesn't matter if you zero it; if it was $0F before and the internal echo length value was based on this, the echo offset will go all the way to its maximum. So let's say it's near its maximum and you enable echo write, you get a write way past the end of the echo buffer. As Bregalad says, you must assume that when you write EDL, the echo offset is just past zero, and EDL is $0F. Anomie says 1/4 second maximum wait in his doc; I haven't bothered to verify his calculation.

I'm putting together my code. It only occasionally fails to load; maybe someone can figure it out. I think you'll find this approach much simpler (credit to Anti Resonance for his SPC2ROM code a while back when I was writing this).

Posted: Sat Feb 27, 2010 2:44 pm
by blargg
Here's the SPC uploading algorithm, written in C so it could be verified correct: spc_uploader.c

The basic algorhtm is to make copies of the DSP registers and 64K RAM from the SPC file, then upload them.

The DSP registers are patched to disable echo and a few other things, then uploaded using a small routine, rather than trying to use the bootloader.

The RAM is patched to disable the timers, and various other things, and patched with some final loader code which restores CPU registers and sets the registers to their final values before running the SPC.

Once the two patched versions are generated, you just upload the DSP one, execute it, then upload the 64K SPC data and execute it, then restore the four input ports to their final values.