This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

VRC6 IRQ

VRC6 IRQ
by on (#163067)
Hi all,

I'm playing around with the VRC6 / mapper 24 and trying to figure out how IRQs are working.
But no success ...

I've read those threads :

http://wiki.nesdev.com/w/index.php/VRC_IRQ
http://forums.nesdev.com/viewtopic.php?f=2&t=8584
http://forums.nesdev.com/viewtopic.php?f=2&t=7059 (looking in debugger how registers are written to)

If I understand everything correctly, I must write $02 to $F001 because I want to use scanline mode, and I must write the number of scanlines I want to wait to $F000.
Am I right ?

So here's what I've done so far.
In my NMI routine :

Code:
@waitNotSprite0:
    BIT $2002
    BVS @waitNotSprite0

    LDA #$10     ; arbitrary value, 10th scanline ?
    STA $F000

    LDA #$02     ; $02 because I want to use scanline mode
    STA $F001

    CLI


In my IRQ routine :

Code:

    SEI

    LDX #%00011111      ; sprites + background + monochrome
    STX $2001
    LDY #21
:
    DEY
    BNE :-
    LDA <MASK_VAR
    STA $2001



I tried some emulators (FCEUX, Nestopia, Nintendulator - which seems to be the most accurate one), and I get 3 different results ...

Did I miss something ?
Should I use the cycle mode and count the scanlines myself ?

Any advice is welcome !
Re: VRC6 IRQ
by on (#163110)
The "scanline" counter is just a convenient divider on top of the regular cycle counter. It doesn't actually count scanlines, it merely counts a number of cycles equivalent to a scanline. There's no reason to use the other mode, unless you want a finer cycle count.

Because it's not based on actual rendering operations at all, and is really just a cycle counter, the timing for when you actually start it is important. I can't speak to the accuracy of any of those emulators, but because the start timing affects the IRQ's timing (unlike a true scanline counter that fires based on PPU addressing), the VRC6 is a lot more sensitive. In this example, if it's in response to a sprite 0 hit, any variance in sprite 0 timing emulation is going to affect your results.
Re: VRC6 IRQ
by on (#163112)
Random thoughts-
1- How do you guarantee that the Spr0 flag is set?
2- you're not acknowledging the IRQ in your IRQ handler
Re: VRC6 IRQ
by on (#163113)
Maybe the problem is you're changing the I flag inside the NMI? When the NMI fires, the status flags are pushed into the stack along with the program counter, and when you RTI from it the flags are restored. This means that if I was set when the NMI fired, it will get set again when you leave the NMI, so the CLI you have there will not work (unless the IRQ fires before you return from the NMI).
Re: VRC6 IRQ
by on (#163117)
Might be worth mentioning that both the NMI and the IRQ have an implied SEI when they fire. RTI recovers the previous state, so for an IRQ handler the RTI is an implied CLI (since it had to be clear for it to fire), but RTI from an NMI just restores whatever state you had prior.
Re: VRC6 IRQ
by on (#163121)
What you probably want to do is initialize the mapper in the main thread, preventing it from generating interrupts, and then clear the I flag, still in the main thread. Then, in the NMI and IRQ handlers, you manipulate only the mapper, leaving the I flag alone. Or maybe still clear it in the NMI handler, if it bleeds into the visible frame, which is actually pretty common if you have music and other things running from the NMI.
Re: VRC6 IRQ
by on (#163449)
Sorry for the late answer, and thanks to all for your explainations !
It makes things clearer.

In the main thread, before my "forever loop", if I disable the mapper's IRQ function, and clear the I flag, does the IRQ routine should be triggered ? Or should anything happen until I enable the mapper's IRQ function ?
Re: VRC6 IRQ
by on (#164438)
So I've made a test rom (attached with source code) to demonstrate my problem.

In my main thread, I'm initializing the VRC6 irq like this :

Code:
    LDA #$00
    STA $F001


So from my understanding of the wiki, it should disable the irq.

Then I do :

Code:
    CLI

:
    JMP :-


At this point, it should never execute my irq handler right ? Or am I really missing something here ?

By the way, here's my irq handler :

Code:
    INC irqCheck
    STA $F002

    RTI


So even if it's executed, it should acknowledge the irq and don't retrigger it after that. Right ?

Sorry to insist, but I really want to understand this.
Re: VRC6 IRQ
by on (#164439)
Quote:
CLI
At this point, it should never execute my irq handler right ?


Just making sure you understand... SEI turns OFF IRQs and CLI turns ON IRQs.
Re: VRC6 IRQ
by on (#164441)
dougeff wrote:
Quote:
CLI
At this point, it should never execute my irq handler right ?


Just making sure you understand... SEI turns OFF IRQs and CLI turns ON IRQs.


Yes I get that, but if IRQs are turned ON and no irq is triggered, it shouldn't call the irq handler no ?
Re: VRC6 IRQ
by on (#164442)
Are you making sure to acknowledge/disable both APU IRQs (frame counter and DMC completion)?
Re: VRC6 IRQ
by on (#164443)
tepples wrote:
Are you making sure to acknowledge/disable both APU IRQs (frame counter and DMC completion)?


Well spotted Tepples !

I've added :

Code:

    LDA #$40
    STA $4017  ; APU IRQ: OFF!
    LDA $4015  ; APU IRQ: ACK!



And it seems to be working now.

Thanks !