NMI & IRQ
Moderator: Moderators
NMI & IRQ
- If both are pending to trigger, I'm allowing the NMI to trigger first, then the IRQ at the next instruction / byte fetch. Is this correct?
Zepper
RockNES author
RockNES author
- Yes.
- I don't remember of a test ROM for this behaviour though... does it exist?
- I don't remember of a test ROM for this behaviour though... does it exist?
Zepper
RockNES author
RockNES author
Some situations get a little tricky. For example, suppose an IRQ is pending, then during the first four cycles of the 7-cycle interrupt sequence an NMI occurs. The CPU will then continue the seven-cycle sequence (no new sequence begins), but it will jump to ($FFFA) as if the first interrupt were an NMI instead of an IRQ. If the NMI occurs during the fifth or sixth cycle of the seven-cycle sequence, a new seven-cycle sequence will begin immediately after the conclusion of the current sequence (with the value of PC pushed to the stack being the same asthe ($FFFE) vector). Finally, if the NMI comes during the last cycle, one instruction of the IRQ handler will execute before the NMI is processed.
A similar phenomenon exists if BRK is interrupted by NMI. If the NMI comes during the first four cycles of BRK, the CPU will treat the BRK as if it were the NMI and jump to ($FFFA). However, the B flag will still be set in the processor flags on the stack, and the return address on the stack will still point to the instruction after BRK (instead of pointing to the BRK). Thus, if a program used BRK and if there was a possibility of an NMI occurring during the BRK, that program would have to test for the B flag in both the NMI and IRQ handlers, since either of them could have the flag set.
A similar phenomenon exists if BRK is interrupted by NMI. If the NMI comes during the first four cycles of BRK, the CPU will treat the BRK as if it were the NMI and jump to ($FFFA). However, the B flag will still be set in the processor flags on the stack, and the return address on the stack will still point to the instruction after BRK (instead of pointing to the BRK). Thus, if a program used BRK and if there was a possibility of an NMI occurring during the BRK, that program would have to test for the B flag in both the NMI and IRQ handlers, since either of them could have the flag set.
"Last version was better," says Floyd. "More bugs. Bugs make game fun."
Test ROM: nmi_during_brk.zip
Result when run on NES:
NMI BRK X
$26 $36 $00
$26 $36 $00
$36 $00 $00
$36 $00 $00
$36 $00 $00
$36 $00 $00
$36 $00 $00
$26 $36 $00
$26 $36 $00
PASSED
Test has NMI occur one clock later on each successive row, such that it eventually suppresses the BRK (apparently there's a 5-clock window for this). First column is the processor status on the stack when the NMI occurs, second when BRK occurs (zero if it didn't occur), third should always be zero.
As you can see, when the BRK is suppressed, the B flag (bit 4) is set in the status during NMI.
(If I think of a way to test NMI during IRQ this cleanly, I'll code and post)
Result when run on NES:
NMI BRK X
$26 $36 $00
$26 $36 $00
$36 $00 $00
$36 $00 $00
$36 $00 $00
$36 $00 $00
$36 $00 $00
$26 $36 $00
$26 $36 $00
PASSED
Test has NMI occur one clock later on each successive row, such that it eventually suppresses the BRK (apparently there's a 5-clock window for this). First column is the processor status on the stack when the NMI occurs, second when BRK occurs (zero if it didn't occur), third should always be zero.
As you can see, when the BRK is suppressed, the B flag (bit 4) is set in the status during NMI.
(If I think of a way to test NMI during IRQ this cleanly, I'll code and post)
that's why I thought MMC3 would work. You can trigger the IRQ any time with a $2007 read/write under the right conditions (which you can set up beforehand)
Using that would require minimal code changes from what you have now. Just replace the BRK with like a $2007 read, put some $2006 writes just prior to it and maybe adjust your wait time to accomidate.
Using that would require minimal code changes from what you have now. Just replace the BRK with like a $2007 read, put some $2006 writes just prior to it and maybe adjust your wait time to accomidate.
-
- Posts: 4
- Joined: Sun Dec 30, 2007 4:42 am
Yes, same here... ^_^;; I'm doing a deep examination... but supposely, it's waiting for a NMI or IRQ to occur.FentonCole wrote:Inside the sync_nmi routine, I noticed that the beq instruction branches directly to cmp and not lda. Was this intentional? I seem to get stuck inside this loop on the very last test since the nmi flag hasn't been set at that point yet. Nice work nevertheless.
Zepper
RockNES author
RockNES author
I finally got an NMI interrupting an IRQ at varying times: nmi_during_irq.zip
Sorry for terseness, I just don't have the energy to do more. I can answer questions.
Sorry for terseness, I just don't have the energy to do more. I can answer questions.
Code: Select all
; Critical test code
lda #0
clv
sec
; Z and C set, others clear
; NMI occurs here first,
lda #1 ; clear Z flag
; then here for two clocks,
clc ; clear C flag
; then here.
; IRQ always occurs here.
sec
...
; IRQ handler is the same except it saves into irq_flag
nmi:
...
pla ; save status byte from stack
sta nmi_flag
pha
bit $4015 ; clear APU IRQ flag
...
rti
Each row of the following table is for NMI occurring one clock later than the previous.
NMI IRQ
-----------------------------------------------------------
$23 $00 NMI occurs before LDA #1
$21 $00 NMI occurs after LDA #1 (Z flag clear)
$21 $00
$20 $00 NMI occurs after CLC, interrupting IRQ
$20 $00
$20 $00
$20 $00
$20 $00
$20 $00
$20 $00 Same result for 7 clocks before IRQ is vectored
$24 $20 IRQ occurs, then NMI occurs immediately after
$24 $20