SPC700 timers
Moderator: ZSNES Mods
SPC700 timers
I followed anomie's document and sfsound.txt to try and emulate the SPC700 timers, would anyone mind taking a quick look and see if I got it right, or if there are any glaring mistakes? For the life of me I can't seem to figure out what ZSNES is doing with the timers, every time I poll them I get totally random values. I know ZSNES' SPC700 core runs way faster than its supposed to, but since the timers are based on SPC700 clock cycles, I can't understand what's going on.
The source code and some sample runs is here:
http://byuu.org/files/spc_timers.txt
(I removed everything not related to the timers from the routines)
The main questions I have are:
1) anomie's document doesn't mention what happens when you read TnOUT registers, but sfsound.txt says it resets "CN0". Does this just reset the stage 3 counter only?
2) Do 0->1 transitions in $f1/writes to $fd-$ff reset both stage 2 and 3 timers?
3) In spc700.txt, I see this:
"Stage 1: 128:1 (T0, T1) or 16:1 (T2) scaler.
Stage 2: 1-256 'divisor', based on a 0-255 wraparound counter and a post-increment comparator."
What's with the 0-255 wraparound counter? This plus sfsound.txt's cryptic description lead me to believe that stage 1 was incremented until it wrapped at 256, and THEN it sent a pulse to stage 2. But that results in an unbelievably slow counter (t2 = 250 ticks/second max). But if that isn't the case, then why even have a stage 1 counter? Why not just say the cycle counter that sends pulses to stage 2 runs nonstop instead?
4) I couldn't follow what happens when you write to TnTARGET while the timer is active, but it's probably not important anyway.
Also, somewhat offtopic. What's up with bits 4-5 in $f1? If they set $f4-$f7 to zero, but the CPU doesn't see it, then why bother setting them to zero? If the APU tries to read from them, it gets the CPU-side values, so ... what gives?
The source code and some sample runs is here:
http://byuu.org/files/spc_timers.txt
(I removed everything not related to the timers from the routines)
The main questions I have are:
1) anomie's document doesn't mention what happens when you read TnOUT registers, but sfsound.txt says it resets "CN0". Does this just reset the stage 3 counter only?
2) Do 0->1 transitions in $f1/writes to $fd-$ff reset both stage 2 and 3 timers?
3) In spc700.txt, I see this:
"Stage 1: 128:1 (T0, T1) or 16:1 (T2) scaler.
Stage 2: 1-256 'divisor', based on a 0-255 wraparound counter and a post-increment comparator."
What's with the 0-255 wraparound counter? This plus sfsound.txt's cryptic description lead me to believe that stage 1 was incremented until it wrapped at 256, and THEN it sent a pulse to stage 2. But that results in an unbelievably slow counter (t2 = 250 ticks/second max). But if that isn't the case, then why even have a stage 1 counter? Why not just say the cycle counter that sends pulses to stage 2 runs nonstop instead?
4) I couldn't follow what happens when you write to TnTARGET while the timer is active, but it's probably not important anyway.
Also, somewhat offtopic. What's up with bits 4-5 in $f1? If they set $f4-$f7 to zero, but the CPU doesn't see it, then why bother setting them to zero? If the APU tries to read from them, it gets the CPU-side values, so ... what gives?
Re: SPC700 timers
Only one glaring mistake, and that's actually something TRAC and I discovered recently. The TnOUT registers are not reset on write. However, most of the memory-targeting MOV instructions actually seem to act like read-modify-write instructions ($AF and $FA are the only exceptions, and $DA (MOVW) reads the low but not the high byte of the word). So it's the rather pointless read cycle in "MOV $ff, #$00" that's actually resetting T2OUT.byuusan wrote:would anyone mind taking a quick look and see if I got it right, or if there are any glaring mistakes?
Yes it does: "Stage 3 mey be read from TnOUT, and the value is zeroed on read."1) anomie's document doesn't mention what happens when you read TnOUT registers, but sfsound.txt says it resets "CN0". Does this just reset the stage 3 counter only?
0->1 in $f1 resets both. Reading $fd-$ff resets only Stage 3. Writing $fd-$ff does nothing (see above).2) Do 0->1 transitions in $f1/writes to $fd-$ff reset both stage 2 and 3 timers?
The Stage 2 description is so confusing because of #4 there. Basically, Stage 1 counts up to 128 or 16, then ticks and resets. Stage 2 increments (in the range 0-255, i.e. it's 8 bits) then compares itself for equality to target to determine whether to tick-and-reset or not. So if you go and set target >= the current value of Stage 2, it will have to count all the way up to 255 and wrap around before it can compare equal to target. So the first tick to Stage 3 might be delayed much longer than otherwise expected.3) In spc700.txt, I see this:
"Stage 1: 128:1 (T0, T1) or 16:1 (T2) scaler.
Stage 2: 1-256 'divisor', based on a 0-255 wraparound counter and a post-increment comparator."
What's with the 0-255 wraparound counter? This plus sfsound.txt's cryptic description lead me to believe that stage 1 was incremented until it wrapped at 256, and THEN it sent a pulse to stage 2. But that results in an unbelievably slow counter (t2 = 250 ticks/second max). But if that isn't the case, then why even have a stage 1 counter? Why not just say the cycle counter that sends pulses to stage 2 runs nonstop instead?
4) I couldn't follow what happens when you write to TnTARGET while the timer is active, but it's probably not important anyway.
Anyway, it looks like you have it right, why not try it?

It sets the value the SPC700 will read; it overrides the CPU-side values, until the CPU sets new values. Useful for getting into a known state before you start waiting for a command byte.Also, somewhat offtopic. What's up with bits 4-5 in $f1? If they set $f4-$f7 to zero, but the CPU doesn't see it, then why bother setting them to zero? If the APU tries to read from them, it gets the CPU-side values, so ... what gives?
Re: SPC700 timers
Fascinating. Are you going to go through and test all of the opcodes individually and document this behavior? I could give you a hand with a few of them if you like.The TnOUT registers are not reset on write. However, most of the memory-targeting MOV instructions actually seem to act like read-modify-write instructions ($AF and $FA are the only exceptions, and $DA (MOVW) reads the low but not the high byte of the word). So it's the rather pointless read cycle in "MOV $ff, #$00" that's actually resetting T2OUT.
Hmm, my fault again. I don't know how I miss these things sometimes...Yes it does: "Stage 3 mey be read from TnOUT, and the value is zeroed on read."
Oooooh. Your stage 1 is the cycle counter. Now it makes perfect sense. I thought stage 1 was a counter that only incremented once every 16/128 cycles. Hence why I have a useless extra counter in there.The Stage 2 description is so confusing because of #4 there. Basically, Stage 1 counts up to 128 or 16, then ticks and resets.
Hm, the best way I can think of emulating this will be to set writes to $fa-$fc to temp_TnTARGET, and then only change the TnTARGET to whatever the temp_ variable is when it actually wraps back to zero via the current TnTARGET value, unless of course you write to TnTARGET when the timer is disabled in $f1 bits 2,1,0.So if you go and set target >= the current value of Stage 2, it will have to count all the way up to 255 and wrap around before it can compare equal to target. So the first tick to Stage 3 might be delayed much longer than otherwise expected.
Well, I've got a million and a half other bugs/problems in my SPC700 core, so I can only run tiny snippet programs I write myself at the moment. And I didn't want to dredge out the old copier, so I was relying on the results from the almighty ZSNES again :DAnyway, it looks like you have it right, why not try it? ;)
But if you say my code's good, I trust that a lot more than the results from... well, you get the idea ;)
That answers all of my questions and then some. Fantastic post, thank you much.
-
- ZSNES Shake Shake Prinny
- Posts: 5632
- Joined: Wed Jul 28, 2004 4:15 pm
- Location: PAL50, dood !
Re: SPC700 timers
Man.byuusan wrote:For the life of me I can't seem to figure out what ZSNES is doing with the timers, every time I poll them I get totally random values.
(...)
I was relying on the results from the almighty ZSNES again
Code: Select all
<grinvader> hmm, how could we enhance our spc700 sync/core ?
<grinvader> it would be cool to suddenly fix 90% of games having trouble
<grinvader> like BOF2 , actraiser 2 and cuonpa
<pagefault> we need to enable cycle counting first
<grinvader> we currently DO NOT count the spc700 cycles ?
<grinvader> * facepalms
(...)
<pagefault> the problem with games is not really SPC cycle counting
<pagefault> it's 65816->SPC ratio
<grinvader> isn't it something like 1 for 4 ?
<grinvader> (or anything simple like that ?)
<pagefault> well yeah
<pagefault> but the 65816 has to be accurate
Or anything critically important timing-wise.
皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
Code: Select all
<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
Code: Select all
<grinvader> we currently DO NOT count the spc700 cycles ?
<grinvader> * facepalms
Holy......... wow. Well, that certainly explains it then. I figured that ZSNES would at least have the little SPC700 cycle count table in there. With just that alone, the timers would work. The 65816<>SPC700 ratio would be irrelevent to the timer results.
As far as syncing the CPU with the APU, I recently came up with perhaps the simplest implementation possible. Just use this code:
Code: Select all
//frequencies reduced by LCD of 8 so that debt.sync doesn't overflow/underflow as easily.
#define CPUFREQ (21477272 / 8)
#define APUFREQ (24576000 / 8)
struct { int debt; }sync;
void add_apu_cycles(int cycles) { sync.debt -= CPUFREQ * cycles; }
void add_cpu_cycles(int cycles) { sync.debt += APUFREQ * cycles; }
void run() {
if(sync.debt >= 0) { run_apu(); }
else { run_cpu(); }
}
While we're on the topic of ZSNES, I may have spotted a potential bug. A while back, ZSNES implemented not clearing WRAM on reset. Shortly after, the same was done for the SPCRAM. However, I noticed ZSNES starts SPC700 execution at 0xffc9 instead of 0xffc0. That skips the stack initialization + RAM initialization of 0x0001-0x00ef (0x0001 is not a typo) to 0x00. Combined with you now clearing the SPCRAM... that might cause some issues if you don't still manually clear that area of RAM upon reset. And I can't imagine why you would if you cleared the entire thing upon reset before. I don't have the latest build to check into that, but it might be worth looking into.
-
- ZSNES Shake Shake Prinny
- Posts: 5632
- Joined: Wed Jul 28, 2004 4:15 pm
- Location: PAL50, dood !
Wow. This is really helpful. Thanks a lot for pointing it out - it may be the cause of some serious sound issues after reset in some games.byuusan wrote:However, I noticed ZSNES starts SPC700 execution at 0xffc9 instead of 0xffc0. That skips the stack initialization + RAM initialization of 0x0001-0x00ef (0x0001 is not a typo) to 0x00. Combined with you now clearing the SPCRAM... that might cause some issues if you don't still manually clear that area of RAM upon reset. And I can't imagine why you would if you cleared the entire thing upon reset before. I don't have the latest build to check into that, but it might be worth looking into.
皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
Code: Select all
<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
We do have sound issues in Super E.D.F. upon reset. Can you please explain more what you mean by how to properly setup SPCRAM and it's stack on reset (not init)? I couldn't follow so well which parts you meant to say we used to, what we do now, and what we should do.byuusan wrote: While we're on the topic of ZSNES, I may have spotted a potential bug. A while back, ZSNES implemented not clearing WRAM on reset. Shortly after, the same was done for the SPCRAM. However, I noticed ZSNES starts SPC700 execution at 0xffc9 instead of 0xffc0. That skips the stack initialization + RAM initialization of 0x0001-0x00ef (0x0001 is not a typo) to 0x00. Combined with you now clearing the SPCRAM... that might cause some issues if you don't still manually clear that area of RAM upon reset. And I can't imagine why you would if you cleared the entire thing upon reset before. I don't have the latest build to check into that, but it might be worth looking into.
You also mention that a large segment of SPC RAM should be set to 0x00 on reset. Since when is SPC RAM ever set to 0x00 for a segment longer than 32 bytes? On init it alternates 0xFF and 0x00.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
Sorry, I'll try to be more clear.
We know that upon SNES power-on, SPCRAM is initialized to random values that vary depending on who does the test.
We also know that upon SNES reset, SPCRAM is not touched at all. However, the IPLROM is enabled in register $f1, and the PC is set to 0xffc0. The flag register is (as a best guess) set to 0x02.
The IPLROM disassembly is as follows, keep in mind that the P flag is cleared upon reset as well:
For those who can't follow the SPC700 code, it's equivalent to:
The above code is never executed in ANY version of ZSNES.
Now, ZSNES used to clear the entire 65536-byte region of SPCRAM. This cleared everything, including the above range. So, for whatever reason, ZSNES starts the SPC700 with the PC set to 0xffc9. That is where the SPC700 tells the CPU it's ready to begin a transfer. It worked before because ZSNES was automatically clearing all RAM to whatever value it did (actually, 0xff now that I look -- which would be incorrect). However, now that range (0x01-0xef) is probably not reset anymore, because the first six opcodes are skipped.
You can fix the problem by setting the SPC700 PC register to 0xffc0 upon reset/power-on, as it should have been from the beginning.
This probably won't fix much, but it is a bug nonetheless.
We know that upon SNES power-on, SPCRAM is initialized to random values that vary depending on who does the test.
We also know that upon SNES reset, SPCRAM is not touched at all. However, the IPLROM is enabled in register $f1, and the PC is set to 0xffc0. The flag register is (as a best guess) set to 0x02.
The IPLROM disassembly is as follows, keep in mind that the P flag is cleared upon reset as well:
Code: Select all
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
/*ffc2*/ 0xbd, //mov sp,x
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
/*ffc5*/ 0xc6, //mov (x),a
/*ffc6*/ 0x1d, //dec x
/*ffc7*/ 0xd0, 0xfc, //bne $ffc5
/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa
Code: Select all
stack_pointer = 0xef;
regs.a = regs.x = 0x00;
for(int i=0x00ef;i>0x0000;i--)spcram[i] = 0x00;
Now, ZSNES used to clear the entire 65536-byte region of SPCRAM. This cleared everything, including the above range. So, for whatever reason, ZSNES starts the SPC700 with the PC set to 0xffc9. That is where the SPC700 tells the CPU it's ready to begin a transfer. It worked before because ZSNES was automatically clearing all RAM to whatever value it did (actually, 0xff now that I look -- which would be incorrect). However, now that range (0x01-0xef) is probably not reset anymore, because the first six opcodes are skipped.
You can fix the problem by setting the SPC700 PC register to 0xffc0 upon reset/power-on, as it should have been from the beginning.
This probably won't fix much, but it is a bug nonetheless.
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
Thanks, I think I follow now.byuusan wrote:Sorry, I'll try to be more clear.
Since when? We've had an init table which was proven to be correct for a while now.byuusan wrote: We know that upon SNES power-on, SPCRAM is initialized to random values that vary depending on who does the test.
No.byuusan wrote: Now, ZSNES used to clear the entire 65536-byte region of SPCRAM. This cleared everything, including the above range. So, for whatever reason, ZSNES starts the SPC700 with the PC set to 0xffc9. That is where the SPC700 tells the CPU it's ready to begin a transfer. It worked before because ZSNES was automatically clearing all RAM to whatever value it did (actually, 0xff now that I look -- which would be incorrect).
We init SPCRAM properly on init, and have for a while now.
Code: Select all
void clearSPCRAM()
{
/*
SPC RAM is filled with alternating 0x00 and 0xFF for 0x20 bytes.
Basically the SPCRAM is initialized as follows:
xx00 - xx1f: $00
xx20 - xx3f: $ff
xx40 - xx5f: $00
xx60 - xx7f: $ff
xx80 - xx9f: $00
xxa0 - xxbf: $ff
xxc0 - xxdf: $00
xxe0 - xxff: $ff
*/
unsigned int i;
for (i = 0; i < 65472; i += 0x40)
{
memset(spcRam+i, 0, 0x20);
memset(spcRam+i+0x20, 0xFF, 0x20);
}
}
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
What the hell? That's... weird. It was my understanding that the default power-on state was undefined, and thus just random values. Not that I don't trust ZSNES... but can anyone else confirm this?
How could you even check 0x01-0xef, since the IPLROM clears this range before any program can take control? Though I suppose it doesn't matter.
I'll have to try Panic Bomber World on a copier, because I'm quite certain it won't initialize SPCRAM to ... whatever that is you posted.
Not to mention that since SPCRAM isn't cleared on reset... it must be one of those games like Super EDF that check for that or something.
Thanks for the code though, that'll save me a lot of trouble.
On another note, I have another question, this time about apudsp.txt...
* DSP write to b0:01
* DSP write to c0:60
* DSP write to 80:60
* DSP write to b0:02
* DSP write to c0:0c
* DSP write to 80:21
Just want to make sure it's correct to ignore these writes.
Also, my faux DSP emulation just keeps a 128-byte buffer that acts as RAM for these values. Will this be sufficient to fake the fact that I don't really have all the DSP stuff (BRR decoding, ADSR/GAIN, pitch, echo, reverb, volume, panning, etc. etc. etc.) in there? Or do the values read back change from what was written to them sometimes when DSP things happen?
How could you even check 0x01-0xef, since the IPLROM clears this range before any program can take control? Though I suppose it doesn't matter.
I'll have to try Panic Bomber World on a copier, because I'm quite certain it won't initialize SPCRAM to ... whatever that is you posted.
Not to mention that since SPCRAM isn't cleared on reset... it must be one of those games like Super EDF that check for that or something.
Thanks for the code though, that'll save me a lot of trouble.
I was referring to 1.36. You wanted to know what old versions and new versions do.We init SPCRAM properly on init, and have for a while now.
On another note, I have another question, this time about apudsp.txt...
So then any writes to $80-$ff are ignored? ZSNES doesn't ignore these writes, and games like Zelda 3 attempt to write here. Log:All registers are accessed by the SPC700 setting the address in $00F2, then
reading/writing $00F3. Note that the register addresses use only 7 bits:
$80-$ff are read-only mirrors of $00-$7f. Any unspecified registers/bits are
read/write with no known effect.
* DSP write to b0:01
* DSP write to c0:60
* DSP write to 80:60
* DSP write to b0:02
* DSP write to c0:0c
* DSP write to 80:21
Just want to make sure it's correct to ignore these writes.
Also, my faux DSP emulation just keeps a 128-byte buffer that acts as RAM for these values. Will this be sufficient to fake the fact that I don't really have all the DSP stuff (BRR decoding, ADSR/GAIN, pitch, echo, reverb, volume, panning, etc. etc. etc.) in there? Or do the values read back change from what was written to them sometimes when DSP things happen?
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
It was first discovered by Overload and put into Super Sleuth, then Snes9x and ZSNES copied, at which point Gemfire also became fixed, and then it was copied into SNEeSe too.byuusan wrote:What the hell? That's... weird. It was my understanding that the default power-on state was undefined, and thus just random values. Not that I don't trust ZSNES... but can anyone else confirm this?
That is >3 years old. I don't care for old stuff.byuusan wrote:I was referring to 1.36. You wanted to know what old versions and new versions do.We init SPCRAM properly on init, and have for a while now.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
Except for MOV and MOVW, everything that writes memory is a read-modify-write operation.byuusan wrote:Fascinating. Are you going to go through and test all of the opcodes individually and document this behavior? I could give you a hand with a few of them if you like.
No, just change TnTARGET immediately. If you set TnTARGET higher then everything works as expected, it's only when you go lower that odd things happen.Hm, the best way I can think of emulating this will be to set writes to $fa-$fc to temp_TnTARGET, and then only change the TnTARGET to whatever the temp_ variable is when it actually wraps back to zero via the current TnTARGET value, unless of course you write to TnTARGET when the timer is disabled in $f1 bits 2,1,0.
Well, i haven't *tested* your code, it just looks ok ;)But if you say my code's good, I trust that a lot more than the results from... well, you get the idea ;)
Exactly. For example, in my test ROM i write to $4C and i get sounds. I write the same thing to $CC and I get nothing. random tests on other registers give similar lacks of effect.byuusan wrote:So then any writes to $80-$ff are ignored?
VxENVX, VxOUTX, and ENDX change based on the DSP state. Also, if the echo buffer is enabled then the appropriate area of RAM will have echo data written to it.Or do the values read back change from what was written to them sometimes when DSP things happen?
-
- Lurker
- Posts: 110
- Joined: Sat Sep 04, 2004 7:55 pm
- Location: USA
Panic Bomber World uses the SA-1 chip, so it won't work on a copier. I know there's a cracked ROM of Panic Bomber World, but I don't know what it's for. (The cracked ROM gives a copy-protection error on current emulators; you should use the good ROM anyway. Since this game can't be tested on a copier, maybe compare the behavior to Super Sleuth? Or disassemble it and write a test program to suit?)byuusan wrote: I'll have to try Panic Bomber World on a copier, because I'm quite certain it won't initialize SPCRAM to ... whatever that is you posted.
This signature intentionally contains no text other than this sentence.
Well that ruins it, indeed.
I'm still not convinced RAM is initialized like that. It makes no sense to force the hardware to do something like that. I'll write my own test program to read the contents of SPCRAM and transfer it to SRAM. Hopefully the copier BIOS doesn't overwrite all 64k of SPCRAM before I get access to it, but even a page or two would be enough to verify what Nach mentioned.
I'm still not convinced RAM is initialized like that. It makes no sense to force the hardware to do something like that. I'll write my own test program to read the contents of SPCRAM and transfer it to SRAM. Hopefully the copier BIOS doesn't overwrite all 64k of SPCRAM before I get access to it, but even a page or two would be enough to verify what Nach mentioned.
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
You can test Gemfire on a copier.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
It differs between machines. My Japanese Machine (SN# 15722371) doesn't initialize SPCRAM but PAL Machine does.byuusan wrote:Well that ruins it, indeed.
I'm still not convinced RAM is initialized like that. It makes no sense to force the hardware to do something like that. I'll write my own test program to read the contents of SPCRAM and transfer it to SRAM. Hopefully the copier BIOS doesn't overwrite all 64k of SPCRAM before I get access to it, but even a page or two would be enough to verify what Nach mentioned.
This is the test program that i wrote (~2 years ago).
http://users.tpg.com.au/trauma/temp/spchack.zip
I included the sram from my jap (GD3) and pal machine (SWC)
It would be nice to have someone with an American Machine to also run the program to see what it gives.
Yeah, and if it differs per-machine, then it's not a good idea to make an emulator assume you're running a specific type of machine -- at least not without an option to select the machine you want to emulate. If it weren't for debugging purposes, I'd probably initialize all RAM to rand() at startup. It would help prevent PD ROMs that rely on RAM being a specific value, like Qwertie's stuff.
Your PAL SRAM file looks to have program code in the first 0x3000 bytes or so before that pattern begins (obviously used by the copier BIOS). How sure are you that it isn't that program that's initializing everything else to 0xff/0x00? Keeping in mind how SPC700 programs just love to rewrite themselves whilst running, just disassembling it probably isn' sufficient. This would probably be best tested with a flash cart...
I have reservations that a special program/chip exists on the SNES to manually set RAM/SPCRAM to any particular value on power on. Whatever pattern you're seeing could easily just be various fluctuations based on whatever RAM chips do when first given power.
Oh, and thanks for the code. I only have two Japanese units though, so I'm afraid I can't help you there.
Your PAL SRAM file looks to have program code in the first 0x3000 bytes or so before that pattern begins (obviously used by the copier BIOS). How sure are you that it isn't that program that's initializing everything else to 0xff/0x00? Keeping in mind how SPC700 programs just love to rewrite themselves whilst running, just disassembling it probably isn' sufficient. This would probably be best tested with a flash cart...
I have reservations that a special program/chip exists on the SNES to manually set RAM/SPCRAM to any particular value on power on. Whatever pattern you're seeing could easily just be various fluctuations based on whatever RAM chips do when first given power.
Oh, and thanks for the code. I only have two Japanese units though, so I'm afraid I can't help you there.
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
If it just differs on Japanse vs. US and Europe, it should be init'd via the country detected of the ROM you're loading.byuusan wrote:Yeah, and if it differs per-machine, then it's not a good idea to make an emulator assume you're running a specific type of machine -- at least not without an option to select the machine you want to emulate.
You'll break real games too like Gemfire and Panic Bomber World.byuusan wrote: If it weren't for debugging purposes, I'd probably initialize all RAM to rand() at startup. It would help prevent PD ROMs that rely on RAM being a specific value, like Qwertie's stuff.
Overload:
If you're saying Japanese games don't need to rely on a specific initlization, how do you explain the init fixed PBW?
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
If you disable sound on the SWC it doesn't transfer any code to SPCRAM. This did work on my copier 2 years ago but unfortunately the NVRAM doesn't work anymore, so once you switch off the SWC it doesn't save the settings anymore. You can also get your hands on the 'Super Wildcard DX2 BIOS' and test in your emulator.byuusan wrote:Your PAL SRAM file looks to have program code in the first 0x3000 bytes or so before that pattern begins (obviously used by the copier BIOS). How sure are you that it isn't that program that's initializing everything else to 0xff/0x00? Keeping in mind how SPC700 programs just love to rewrite themselves whilst running, just disassembling it probably isn' sufficient. This would probably be best tested with a flash cart...
I have reservations that a special program/chip exists on the SNES to manually set RAM/SPCRAM to any particular value on power on. Whatever pattern you're seeing could easily just be various fluctuations based on whatever RAM chips do when first given power.
I see no reason why this pattern could be set at init. Remember there are two APU versions, maybe the japanese machines that we have the first version whereas my PAL machine might have version 2.
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
Okay, that's 3 games we know needs init then.
We really should keep a list of stuff like this somewhere...
I guess it's possible for US developers to overlook this since they're testing on US hardware, which explains for Gemfire and Super Battleship. But what exactly happened with the Japanese release Panic Bomber World? Could it be later SFCs do init and that's what it was tested on, and no one tried it on an earlier one or complained for there to be a R1.1? Or perhaps the SA-1 does initing?
We really should keep a list of stuff like this somewhere...
I guess it's possible for US developers to overlook this since they're testing on US hardware, which explains for Gemfire and Super Battleship. But what exactly happened with the Japanese release Panic Bomber World? Could it be later SFCs do init and that's what it was tested on, and no one tried it on an earlier one or complained for there to be a R1.1? Or perhaps the SA-1 does initing?
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
It could just be any random thing that results in PBW working. Maybe an opcode has a wrapping bug and it just happens to read the 0x00 you set, whereas before it was getting 0xff which caused the code to crash? Perhaps Japanese systems don't initialize SPCRAM, but they still end up with certain values in certain spots that just makes the game work? Perhaps it's because that bug I mentioned above about starting the SPC at 0xffc9 was responsible?
I'll try and tear apart the code from Gemfire/Super Battleship and see what I find. I wonder what you'd even take advantage of by assuming the RAM is striped at poweron. I guess the easy way would to be to do a tracelog of SPC700 commands with RAM initialized and with it not. I should be able to spot the first difference pretty easily that way. Hopefully my POS SPC700 code will run either game yet :/
I also assume that all of these games have handlers for when you reset the game, like Super EDF, otherwise its own changes to RAM could break itself.
I'll try and tear apart the code from Gemfire/Super Battleship and see what I find. I wonder what you'd even take advantage of by assuming the RAM is striped at poweron. I guess the easy way would to be to do a tracelog of SPC700 commands with RAM initialized and with it not. I should be able to spot the first difference pretty easily that way. Hopefully my POS SPC700 code will run either game yet :/
I also assume that all of these games have handlers for when you reset the game, like Super EDF, otherwise its own changes to RAM could break itself.
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
It just happens to work in 3 different games???byuusan wrote:It could just be any random thing that results in PBW working. Maybe an opcode has a wrapping bug and it just happens to read the 0x00 you set, whereas before it was getting 0xff which caused the code to crash? Perhaps Japanese systems don't initialize SPCRAM, but they still end up with certain values in certain spots that just makes the game work? Perhaps it's because that bug I mentioned above about starting the SPC at 0xffc9 was responsible?
And we're not just talking in ZSNES here, the exact same problems were in Snes9x too till we did the RAM init there.
There were also some hacks we found were no longer needed which hacked SPC RAM for certain games, perhaps it would be an idea to look into them to see if the RAM init fixed those as well.
Based on the evidence, I don't think it just happens to work, or see how what ZSNES did regarding starting the SPC was related to Snes9x.
Would have to talk to TRAC, but I'm pretty sure he said when he did the init, it fixed Gemfire for him too.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding