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_IRQhttp://forums.nesdev.com/viewtopic.php?f=2&t=8584http://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 !
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.
Random thoughts-
1- How do you guarantee that the Spr0 flag is set?
2- you're not acknowledging the IRQ in your IRQ handler
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).
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.
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.
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 ?
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.
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.
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 ?
Are you making sure to acknowledge/disable both APU IRQs (frame counter and DMC completion)?
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 !