NMI timing

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
JonteP
Posts: 10
Joined: Tue Aug 14, 2018 5:32 am

NMI timing

Post by JonteP »

Hi all!

So, I'm writing yet another NES emulator, for my own amusement and learning purposes. I've got most of the basic stuff working and decided to dive into some log standing timing issues.

I'm currently failing blargg's NMI timing test (05-nmi_timing, from ppu_vbl_nmi test suite).

Each loop of my CPU code is an instruction and it calls PPU/APU as needed to let them catch up before reads/writes. I poll interrupts at the second-to-last cycle, except in branches and interrupt routines.

This is my output:
4, 3, 3, 3, 3, 3, 3, 2, 2, 2

And a more detailed log:
STA 0x2000.7: x 326 y 240
LDX: x 326 y 240
Interrupt polling: x 329 y 240
LDX: x 332 y 240
Interrupt polling: x 335 y 240
LDX: x 338 y 240
Interrupt polling: x 0 y 241
NMI triggered: x 1 y 241
LDX: x 3 y 241
Interrupt polling: x 6 y 241
Load NMI pointer:x 9 y 241

STA 0x2000.7: x 327 y 240
LDX: x 327 y 240
Interrupt polling: x 330 y 240
LDX: x 333 y 240
Interrupt polling: x 336 y 240
LDX: x 339 y 240
NMI triggered: x 1 y 241
Interrupt polling: x 1 y 241
Load NMI pointer:x 4 y 241

STA 0x2000.7: x 328 y 240
LDX: x 328 y 240
Interrupt polling: x 331 y 240
LDX: x 334 y 240
Interrupt polling: x 337 y 240
LDX: x 340 y 240
NMI triggered: x 1 y 241
Interrupt polling: x 2 y 241
Load NMI pointer:x 5 y 241

STA 0x2000.7: x 329 y 240
LDX: x 329 y 240
Interrupt polling: x 332 y 240
LDX: x 335 y 240
Interrupt polling: x 338 y 240
LDX: x 0 y 241
NMI triggered: x 1 y 241
Interrupt polling: x 3 y 241
Load NMI pointer:x 6 y 241

STA 0x2000.7: x 330 y 240
LDX: x 330 y 240
Interrupt polling: x 333 y 240
LDX: x 336 y 240
Interrupt polling: x 339 y 240
NMI triggered: x 1 y 241
LDX: x 1 y 241
Interrupt polling: x 4 y 241
Load NMI pointer:x 7 y 241

STA 0x2000.7: x 331 y 240
LDX: x 331 y 240
Interrupt polling: x 334 y 240
LDX: x 337 y 240
Interrupt polling: x 340 y 240
NMI triggered: x 1 y 241
LDX: x 2 y 241
Interrupt polling: x 5 y 241
Load NMI pointer:x 8 y 241

STA 0x2000.7: x 332 y 240
LDX: x 332 y 240
Interrupt polling: x 335 y 240
LDX: x 338 y 240
Interrupt polling: x 0 y 241
NMI triggered: x 1 y 241
LDX: x 3 y 241
Interrupt polling: x 6 y 241
Load NMI pointer:x 9 y 241

STA 0x2000.7: x 333 y 240
LDX: x 333 y 240
Interrupt polling: x 336 y 240
LDX: x 339 y 240
NMI triggered: x 1 y 241
Interrupt polling: x 1 y 241
Load NMI pointer:x 4 y 241

STA 0x2000.7: x 334 y 240
LDX: x 334 y 240
Interrupt polling: x 337 y 240
LDX: x 340 y 240
NMI triggered: x 1 y 241
Interrupt polling: x 2 y 241
Load NMI pointer:x 5 y 241

STA 0x2000.7: x 335 y 240
LDX: x 335 y 240
Interrupt polling: x 338 y 240
LDX: x 0 y 241
NMI triggered: x 1 y 241
Interrupt polling: x 3 y 241
Load NMI pointer:x 6 y 241
Any input is much appreciated!
User avatar
zeroone
Posts: 939
Joined: Mon Dec 29, 2014 1:46 pm
Location: New York, NY
Contact:

Re: NMI timing

Post by zeroone »

Does Nintendulator pass that particular test?
JonteP
Posts: 10
Joined: Tue Aug 14, 2018 5:32 am

Re: NMI timing

Post by JonteP »

zeroone wrote:Does Nintendulator pass that particular test?
I'll be sure to check that out!

I found that I can pass the test by polling NMI 2 ppu cycles earlier. Basically I was polling it at the first ppu cycle of the last CPU cycle of the instruction. Not sure if this is a hack or proper fix though....
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: NMI timing

Post by Zepper »

I'll help you. Firstly, about $2002 reads...

Code: Select all

8) Reading (VBlank) flag 4 PPU clocks before set shouldn't suppress NMI
2) Reading flag 3 PPU clocks before set shouldn't suppress NMI
5) Reading flag 2 PPU clocks before set shouldn't suppress NMI
9)*Reading flag 1 PPU clock before set should suppress NMI
3)*Reading flag when it's set should suppress NMI
6)*Reading flag 1 PPU clock after set should suppress NMI
10)Reading flag 2 PPU clocks after set shouldn't suppress NMI
4) Reading flag 3 PPU clocks after set shouldn't suppress NMI
7) Reading flag 4 PPU clocks after set shouldn't suppress NMI
Next, about $2002 writes, the NMI is suppressed if disabled by bit 7 and the VBlank flag is still set. Plus, the NMI is requested if bit 7 is set and the current PPU cycle isn't zero.
zeroone wrote:Does Nintendulator pass that particular test?
Yes.
nmi_nintendulator.png
nmi_nintendulator.png (6.53 KiB) Viewed 11134 times
JonteP
Posts: 10
Joined: Tue Aug 14, 2018 5:32 am

Re: NMI timing

Post by JonteP »

Thanks, Zepper!

I don't think this has to do with NMI suppression. This is testing the number of instructions between NMI trigger and the NMI instruction. Seems that shifting back NMI polling a couple ppu cycles fixes this, and I pass that whole test suite now. I also played through stage 2 in Battletoads without problems.

Now on to tackle IRQs which are currently very inaccurate.
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: NMI timing

Post by Zepper »

JonteP wrote:Seems that shifting back NMI polling a couple ppu cycles fixes this, and I pass that whole test suite now.
NMI is requested at the end of the dummy scanline. Do you do the same?
JonteP
Posts: 10
Joined: Tue Aug 14, 2018 5:32 am

Re: NMI timing

Post by JonteP »

According to my log above, NMI is triggered at scanline 241 (first vblank scanline) dot 1. Is that wrong?
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: NMI timing

Post by Zepper »

JonteP wrote:According to my log above, NMI is triggered at scanline 241 (first vblank scanline) dot 1. Is that wrong?
You know about the CPU-PPU alignment, right? Well, during my tests, I had to request NMI 1 PPU cycle earlier. In other words, at line 240 cycle 341. Technically, it would be the same, but I clock the PPU before the CPU cycle.
JonteP
Posts: 10
Joined: Tue Aug 14, 2018 5:32 am

Re: NMI timing

Post by JonteP »

Zepper wrote:
JonteP wrote:According to my log above, NMI is triggered at scanline 241 (first vblank scanline) dot 1. Is that wrong?
You know about the CPU-PPU alignment, right? Well, during my tests, I had to request NMI 1 PPU cycle earlier. In other words, at line 240 cycle 341. Technically, it would be the same, but I clock the PPU before the CPU cycle.
Yes, if you mean that they are not running in parallel, I'm aware of it. And I'm inclined to think that this is what I am compensating for.

Anyway, thanks for helping out!
Post Reply