Question about NMI and triggering.

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
urbanspr1nter
Posts: 39
Joined: Thu Aug 16, 2012 7:55 pm

Question about NMI and triggering.

Post by urbanspr1nter » Sat Aug 26, 2017 7:14 am

Hi, I have my CPU for an NES emulator working and it passes nestest.nes. Now I am getting started with writing the PPU, but I am having a hard time actually knowing when an NMI is triggered for a VBLANK.

I am just trying to get the nametable to be written for Donkey Kong -- for something simple first...

If my understanding is correct, the NMI bit is controlled in BIT_7 in $2000. I am turning on this bit when my scanlines hit 241. I set the NMI bit, then the Vblank bit in 2002.

So my cycle is like this (in pseudo-code):

Code: Select all

run() {
    fetchOpcode();
    executeOpcode();
    ppuRun();
    // check NMI here. and execute NMI.
}

ppuRun() {
    incrementPPUCycles();
    if(cycles === 341) ppuScanlines++;
    if(ppuScanlines >= 241 && ppuScanlines <= 260) {
        ppuSetNmi(1);
        ppuSetVblank(1);
    }

    if(ppuScanlines == 261) {
       ppuSetNmi(0);
       ppuSetVblank(0);
    }

    if(ppuScanlines == 262) {
       outputFrame();
       ppuScanlines = 0;
    }
}
Do I have the right idea here? If so, I am having problems actually going into NMI. I actually go into the NMI handler in FFFA/FFFB, but then the instructions are

Code: Select all

PHA
over and over again. My guess is that it's going into the NMI routine in every CPU cycle. Just making sure if i have things conceptually right before going further.

tepples
Posts: 21751
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Question about NMI and triggering.

Post by tepples » Sat Aug 26, 2017 7:49 am

/NMI on a 6502 is edge-sensitive. This means if goes from high (unasserted) to low (asserted), the CPU will call the NMI handler. It will not call the NMI handler again until /NMI goes high then low again. This is why you usually* see only one call to the NMI handler per vblank.

/IRQ, by contrast, is level-sensitive. If a CLI or PHP instruction clears the interrupt priority level bit (I, bit 2 of P) while /IRQ remains low, the CPU will call the IRQ handler again.


* A couple games, such as Bases Loaded, clear bit 7 of $2000 and then set it again without reading $2002 to acknowledge the NMI. These games expect this to cause the CPU to call the NMI handler again.

urbanspr1nter
Posts: 39
Joined: Thu Aug 16, 2012 7:55 pm

Re: Question about NMI and triggering.

Post by urbanspr1nter » Sat Aug 26, 2017 7:52 am

So then, it would make sense to do something along the lines of keeping the previous NMI flag and then check --

if the currentNMI is true, and the previousNMI was false, then run NMI handler?

tepples
Posts: 21751
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Question about NMI and triggering.

Post by tepples » Sat Aug 26, 2017 8:09 am

Yes, you will need to keep track of the previous state of /NMI. Someone familiar with Visual 6502 could find exactly the node that stores the previous state.

urbanspr1nter
Posts: 39
Joined: Thu Aug 16, 2012 7:55 pm

Re: Question about NMI and triggering.

Post by urbanspr1nter » Sat Aug 26, 2017 8:17 am

Cool! that looks like it fixed it...

Looks like my emu isn't stupidly executing PHA over and over again. :)

As far as the IRQ bit goes, that's just as far as checking if the bit is asserted/deasserted on every opcode execution?

User avatar
Zepper
Formerly Fx3
Posts: 3190
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Re: Question about NMI and triggering.

Post by Zepper » Sat Aug 26, 2017 6:43 pm

Not sure if it's useful, information from test ROMs. "Reading flag" means reading $2002 bit $80 (VBlank flag).

Code: Select all

Reading flag 4 PPU clocks before set shouldn't suppress NMI
Reading flag 3 PPU clocks before set shouldn't suppress NMI
Reading flag 2 PPU clocks before set shouldn't suppress NMI
*Reading flag 1 PPU clock before set should suppress NMI
*Reading flag when it's set should suppress NMI
*Reading flag 1 PPU clock after set should suppress NMI
Reading flag 2 PPU clocks after set shouldn't suppress NMI
Reading flag 3 PPU clocks after set shouldn't suppress NMI
Reading flag 4 PPU clocks after set shouldn't suppress NMI

Post Reply