Hello, I'm coding an NES emulator in JavaScript, and currently I'm facing a problem that I can't overcome.
I've not implemented any mappers or scrolling, and toying with simplest games like donkey kong.
DK runs, just that its slow. I've made a forums post previously but I didn't bump it https://forums.nesdev.com/viewtopic.php?f=3&t=16293
The reason for slowness is that in a second, the game is only triggering 20-25 NMIs. MS Pac-man in particular doesn't trigger NMIs at all.
I debugged and compared instruction flow with fceux, and found out that in my emulator, bit 7 of PPUCTRL is being disabled, so the emulator can't do NMI. On further inspection I found out that PPUSTATUS is not being read sometimes by the games. MS pac man reads PPUSTATUS once or twice, then never reads it and as a result the NMI bit is not set and the game renders nothing.
My CPU implementation is good, as it matches the nintendulator nestest.log.
Do any of you guys have any idea that what wrong/missing implementation might be responsible for this?
PPUSTATUS not being read
Moderator: Moderators
Re: PPUSTATUS not being read
Oh, I forgot to mention that i've not implemented APU at all, ignoring writes to the registers and returning 0 on read.
Is handling of APU IRQs required for correct game functioning?
Is handling of APU IRQs required for correct game functioning?
Re: PPUSTATUS not being read
Games don't use PPUSTATUS to detect vblank, except during initialization while waiting for the PPU to become stable. After that, games usually enable NMIs and that's what they use to know when vblank starts. Games may or may not read PPUSTATUS to "acknowledge" the NMI, but that's not necessary since the NMI flag clears itself at the end of vblank. Games may also read PPUSTATUS to reset the $2005/6 hi/lo latch, but that's also optional, so it's highly possible that some games will only use PPUSTATUS during initialization and then never again.
As long as NMIs are enabled via PPUCTRL, they'll fire every time vblank starts, the game code doesn't have to do anything to "trigger" NMIs, they'll fire regardless of what the CPU is doing.MS pac man reads PPUSTATUS once or twice, then never reads it and as a result the NMI bit is not set
Re: PPUSTATUS not being read
If it matters, Ms. Pac-Man is on the tricky list for some edge-case stuff it does with PPUSTATUS. Lolo 2 and Spelunker have the same problem.
These rely on 1 cycle NMI delay when PPUSTATUS ($2002) bit 7 gets set inside vblank (if $2002 has not been read yet), in which PPUSTATUS bit 7 can be read as true.Here's how I understand what's going on in games like that:
- CPU reads $AD (LDA abs) or $2C (BIT abs) from PC++
- CPU reads $02 (low byte of $2002) from PC++
- CPU reads $20 (high byte of $2002) from PC++
Vertical blanking begins between these cycles. /NMI goes low, because the CPU checks for falling edges on /NMI only between instructions, the CPU's interrupt circuit doesn't notice. - CPU reads $80 from $2002
/NMI goes high because the read has acknowledged the interrupt
Re: PPUSTATUS not being read
NMI goes to an S/R latch, so the minimum time will be an analog effect instead of a digital one. (Look at visual6502 nodes "NMIP" and "#NMIP")
Re: PPUSTATUS not being read
Thanks for the replies everyone. I've figured out the error by comparing the execution with fceux & mesen.
I noticed that in my case, write to PPUCTRL was hugely delayed. My emulator is of a catch up design with scanline accuracy.
Due to a bug, the cycle counting algorithm was incorrect which slowed the cpu down.
Now with proper cycle counting, Donkey Kong and pac man are running fine. I'm not introducing any delay after reading ppustatus, although I do NMI right after the first vblank scanline is rendered.
I noticed that in my case, write to PPUCTRL was hugely delayed. My emulator is of a catch up design with scanline accuracy.
Due to a bug, the cycle counting algorithm was incorrect which slowed the cpu down.
Now with proper cycle counting, Donkey Kong and pac man are running fine. I'm not introducing any delay after reading ppustatus, although I do NMI right after the first vblank scanline is rendered.
Re: PPUSTATUS not being read
How exactly does Ms. Pac-Man rely on such a fine timing detail like this? Is it something intentional or is it more like "the game ignores this hardware quirk that luckily prevents the program from crashing"?