I think I've got most of the PPU power/reset behavior and timing determined
and verified with test ROMs (so you can test your emulator too). I put the
findings on the NesDevWiki. As usual, full ca65 source code included.
ppu_power_reset3.zip
EDIT: added test for $2000 low two bits and updated Wiki and test ROMs. Thanks for the trick, dvdmth.
Quote:
- My devcart is locked to single-screen nametable mirroring, so I can't test the low two bits in $2000.
You can use the following $2005/2006 magic to test those two bits:
Code:
bit $2002
lda #0
sta $2005
sta $2005
sta $2005
sta $2006
This will make the active VRAM address either $0000, $0400, $0800, or $0C00, depedning on $2000 bits 0-1. The writes to $2005 cause all 15 bits of the "scroll latch" registers to become clear, except the nametable select bits. The fourth write (the one to $2006) forces the contents of the latch to be transferred to the VRAM address register. Bits 0-1 of $2000 correspond to bits 10-11 of the VRAM address.
After implementing your recent findings, Tiger Heli (U), Kamen Rider Club (J), and maybe more, won't boot in my emu due to PPU register writes being ignored in the 1st frame. These do work by doing a reset afterwards though.
Same here after implementing the ignored writes in my emulator. I extracted the init code from Tiger-Heli and sure enough, it fails to enable NMI often at power on my NES. On further testing, I found that if I power the NES down for several seconds between tests, then it works most of the time. So apparently the VBL flag is usually clear at power if the NES was off for a while, and often set if it was recently on. What's the other game that someone was saying needed the VBL flag set at power?
$2002 power on with $00 instead of $A0:
- Ironsword: locks up at titlescreen with "Ironswor" and no sword in his hands
- Cobra Triangle: locks up when starting game
btw1: I probably don't need to mention that a lot of homebrew stuff fails.
btw2: $2007 read buffer.nes usually succeeds if I leave $2007 read buffer unchanged after reset, instead of setting it to 0
Has emulation accuracy finally reached the point at which the user will have to reload ROMs or <s>blow in the cartridge, or</s> press Reset a bunch of times in order to get games to work? hahaha
Anyway, great work as usual, blargg! Thanks!
Quote:
$2007 read buffer.nes usually succeeds if I leave $2007 read buffer unchanged after reset, instead of setting it to 0
Odd. Are you modifying it during rendering? It should only be modified when the 2A03 reads from $2007 (and its mirrors). The test sets PPUADDR to $0010, which is the beginning of a run of $FF bytes, then reads from PPUDATA, which should put $FF into the buffer. Then it goes into an infinite loop, so the buffer should still contain $FF after reset if your emulator isn't clearing it during reset.
On the hunch that maybe the VBL flag is getting cleared during the first frame, I tried delaying 26000 clocks then reading $2002 after power, and quickly powering off then on several times. I still got $80, so the VBL flag isn't getting cleared before it's next set at ~27384. Oh well.
We need someone with Tiger Heli, Ironsword, and Cobra Triangle (PowerPak won't suffice) to see how often they work when powering up the NES after being off for a while, and after being off for only a couple of seconds. I'm guessing some won't work all the time in these cases. I'm going to see if I can extract the init code from each and test it on my NES.
I found a couple of old threads dealing with this issue
"Let's uncover power-up and reset behavior" and
"APU Frame IRQ Flag and IRQ Timing".
Quote:
Are you modifying it during rendering?
hmmmmm... *shameful yes*
none of your test roms cover it
I can't get Ironsword to not work on my Famicom.
OK, Ironsword doesn't have the problem because the loop that clears APU registers
reads the register first since it uses the STA $4000,x addressing mode. So that reads $4015 after the frame IRQ flag has been set. This game should work regardless of the VBL flag at power. Same issue for Cobra Triangle (I checked init code too).
hap wrote:
Quote:
Are you modifying it during rendering?
hmmmmm... *shameful yes*
none of your test roms cover it
Yes indeed, I need to write one for this. So it's good you had this bug.
Quote:
OK, Ironsword doesn't have the problem because the loop that clears APU registers reads the register first since it uses the STA $4000,x addressing mode. So that reads $4015 after the frame IRQ flag has been set.
Ah, good find, didn't know that that was an "RMW"? instruction. Maybe you could improve your NES CPU opcode test program to include such cases?
I have the PAL Ironsword, but I have trouble to make it working right now, like everyother NES cartridge I have. I have to reset some 60 times or so to get a boot with very corrupted graphics. Seems like a bit of cleaning will be needed.
I think the dummy read for STA ABS,X addressing mode solves the problem, so no NES tests are needed for Ironsword and Cobra Triangle. I still predict that Tiger-Heli will fail if powered down then up without a long delay between.
hap, here's a new test ROM that verifies that $2007 is unchanged during rendering:
Rendering_and_$2007_buf.nes.zip
yeah, that test rom fails here (for now)
Thanks.
Oh lovely, if I power the NES off for 20 seconds or so, at power PPUADDR is $0000, SPRADDR is $2F, and most registers work
immediately, rather than being ignored until 29658. Time for more test rewriting.. maybe I can hit 40 or 50 test ROMs! Bleah.
EDIT: OK, got a big rewrite of the PPU power/reset test ROMs done, and covering these new findings ("only" 37 test ROMs).
NesDevWiki page is updated as well. Main finding was that if the NES is off for 20 seconds or more, all registers work at power, and $2002, $2003, and $2006 are 0.
ppu_power_reset3.zip
Well, also all those findings are true for NTSC U.S. NES, but they may differ greatly for a Japanese Famicom and European PAL NES.
Also, some results may very from unit to unit, for exemple it's well known that the initial palette values are proper to a NES, because they all flashes in different colors.
Yeah, it's too bad I don't have a second US NES, perhaps even a top-loader. I do have a PAL NES and hope to test on it soon. I predict what tepples predicts, that the times will correspond to particular scanlines. Today I'm going to find whether the timing is the same if power is left off for a while between tests, down to a single PPU clock. I'm hoping that the variation was just due to not powering off long enough. If this is the case, it would allow for reliable movie recording and playback between the emulator and NES (either direction), which would be really cool.
Just tested a bunch of Famicom games on an emulator. Following fail to work on it if writes are ignored for a while after reset:
3E785DC3 Air Fortress
8BCDE59A Athena
2B462010 Balloon Fight
DC75732F Cosmic Epsilon
A5E6BAF9 Dragon Slayer 4 - Drasle Family
77DCBBA3 Eggland - Meikyuu no Fukkatsu
240C6DE8 Elysion
E0604F76 F-1 Race
73921674 Family Computer - Othello
79698B98 God Slayer - Haruka Tenkuu no Sonata
8DCD9486 Jumbo Ozaki no Hole in One Professional
D0EB749F Lord of King
D8748E0A Magic John
805F81BC Metal Gear
E2A79A57 Rollerball
8E62D229 Sansuu 1 Nen - Keisan Game
892CBBC2 Sansuu 2 Nen - Keisan Game
98DC1099 Sansuu 3 Nen - Keisan Game
8B4A2866 Sansuu 4 Nen - Keisan Game
Shouldn't come as a big surprise I guess since it most likely works differently on Famicom consoles. Just tought it I'd list them anyway in case someone finds this useful.
Edit: added CRCs
Hmmm, do you mean these fail if writes are ignored after power, or only after game is powered up normally, then reset is "pressed" in the emulator? Are those all non-US releases?
GoodNES says that at least Balloon Fight is (JU).
In my emulator at least, Air Fortress (J) works at power but fails at reset, while Air Fortress (U) works after both. The init code has been changed for the US version, inserting 2 extra VBL wait loops. Since VBL could be set at reset, the first might not wait at all. The second would then wait for the first flag setting, where the registers still wouldn't work. The second two loops are needed, and a read of $2002 before them, which the first loop provides. Their loops also wait until the flag becomes unset, maybe just to be on the safe side, having been bitten by this.
Air Fortress (J)
Code:
INC $C000
[memory clear loop was here]
LDA #$00
STA $2001
LDA $2002 ; wait for VBL
BPL *-3
CLD
LDX #$FF
TXS
INX
STX $2001
...
Air Fortress (U)
Code:
INC $C000
LDA #$00
STA $2000
STA $2001
[MMC1 bank selection]
[memory clear loop was here]
LDA $2002 ; wait for VBL
BPL *-3
LDA $2002
BMI *-3
LDA $2002 ; wait for VBL
BPL *-3
LDA $2002
BMI *-3
LDA $2002 ; wait for VBL
BPL *-3
LDA $2002
BMI *-3
CLD
LDX #$FF
TXS
INX
STX $2001
...
Metal Gear (J) fails after reset, but (U) works. Same for Rollerball and God Slayer (Crystalis).
Well, that's somewhat fun. Also, all games that have a lda $2002 - bmi loop, the only way this branch can be taken more than once is in Nesticle. I wonder why they waster ROM to put this.
Also I've noted the Reset code of many commercial games is somewhat messy. A lot of games does write zero to $2000 and $2001 many times (I now understand that to be sure 2 times are needed, one at reset and one after a couple of frames in cases if the original writes were ignored). However, many games also do stuff like init the stack pointer, set the i flag, clear the d flag up to 3 times (usually each Reset code jumps to a secondary Reset code with redudency tasks, etc...).
blargg wrote:
Hmmm, do you mean these fail if writes are ignored after power, or only after game is powered up normally, then reset is "pressed" in the emulator? Are those all non-US releases?
They fail only when reset is pressed. On
power I'm taking the off-for-more-than-20-secs route, allowing writes go through immediately. The emulator passes your tests in ppu_power_reset3.zip.
AFAIK, all of them are (J) releases but I've edited my post to include their CRCs in case anyone wants to double check. The (U) and (E) versions (including Balloon Fight) work fine.
Some tests fail when I press reset for a second time. Is this "normal"?
Example: the VBlank flag. The wiki says "unchanged" on reset. By pressing reset one time, it passes; if I press a second time, it says "should be zero". The 2003h is the same.
Once a test has reported pass/fail, it's done until you power down the (emulated) NES. If you press reset again, it could give erroneous results. The same goes if it tells you to press reset AFTER the message disappears and you instead press it while the message is still displayed (tests that do this must have PPU rendering off while reset is pressed).
blargg wrote:
Once a test has reported pass/fail, it's done until you power down the (emulated) NES. If you press reset again, it could give erroneous results.
Could you have the program detect a wrong soft reset?
Quote:
The same goes if it tells you to press reset AFTER the message disappears and you instead press it while the message is still displayed (tests that do this must have PPU rendering off while reset is pressed).
"Press reset after the tone", then turn off rendering and play a tone on square 1.