6502 Interupts

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
6502 Interupts
by on (#37416)
Can someone advice me if I am handling interupts correctly here?

I have an Interupt Handler class in my CPU that monitors a flag for NMI and a flag for IRQ once per CPU cycle, if either flag is set, it executes the interupt and then clears the flag:

Code:
    public class InteruptHandler
    {
        public bool IRQInterrupt = false;
        public bool NMIInterrupt = false;       

        public void DoInterupts()
        {
            if (NMIInterrupt)
            {
                triggerNMI();
                NMIInterrupt = false;
            }
            else if (IRQInterrupt)
            {
                TriggerIRQ();
                IRQInterrupt = false;
            }
        }

        public void TriggerIRQ()
        {
            // If I is set, the software wants to mask IRQ interupts.
            if (!CPU.Registers.P.I)
            {
                // Push return address onto stack.
                CPU.Stack.Push((byte)((CPU.PC >> 8) & 0xff));
                CPU.Stack.Push((byte)(CPU.PC & 0xff));

                // Push the status register onto the stack           
                CPU.Stack.Push(CPU.Registers.P.Value);

                // Set Interrupt flag
                CPU.Registers.P.I = true;

                // JMP to interrupt code
                CPU.PC = (CPU.Memory[0xFFFe] | (CPU.Memory[0xFFFF] << 8));
            }
        }

        public void triggerNMI()
        {           
            // Push return address onto stack.
            CPU.Stack.Push((byte)((CPU.PC >> 8) & 0xff));
            CPU.Stack.Push((byte)(CPU.PC & 0xff));

            // Push the status register onto the stack           
            CPU.Stack.Push(CPU.Registers.P.Value);

            // JMP to interrupt code
            CPU.PC = (CPU.Memory[0xFFFA] | (CPU.Memory[0xFFFB] << 8));
        }
    }


DoInterupts() is called at the end of each CPU cycle.

Is this the correct way to implement NMI and IRQ?
Re: 6502 Interupts
by on (#37632)
FlySwat wrote:
Can someone advice me if I am handling interupts correctly here?

I have an Interupt Handler class in my CPU that monitors a flag for NMI and a flag for IRQ once per CPU cycle, if either flag is set, it executes the interupt and then clears the flag:

Code:
    public class InteruptHandler
    {
        public bool IRQInterrupt = false;
        public bool NMIInterrupt = false;       

        public void DoInterupts()
        {
            if (NMIInterrupt)
            {
                triggerNMI();
                NMIInterrupt = false;
            }
            else if (IRQInterrupt)
            {
                TriggerIRQ();
                IRQInterrupt = false;
            }
        }

        public void TriggerIRQ()
        {
            // If I is set, the software wants to mask IRQ interupts.
            if (!CPU.Registers.P.I)
            {
                // Push return address onto stack.
                CPU.Stack.Push((byte)((CPU.PC >> 8) & 0xff));
                CPU.Stack.Push((byte)(CPU.PC & 0xff));

                // Push the status register onto the stack           
                CPU.Stack.Push(CPU.Registers.P.Value);

                // Set Interrupt flag
                CPU.Registers.P.I = true;

                // JMP to interrupt code
                CPU.PC = (CPU.Memory[0xFFFe] | (CPU.Memory[0xFFFF] << 8));
            }
        }

        public void triggerNMI()
        {           
            // Push return address onto stack.
            CPU.Stack.Push((byte)((CPU.PC >> 8) & 0xff));
            CPU.Stack.Push((byte)(CPU.PC & 0xff));

            // Push the status register onto the stack           
            CPU.Stack.Push(CPU.Registers.P.Value);

            // JMP to interrupt code
            CPU.PC = (CPU.Memory[0xFFFA] | (CPU.Memory[0xFFFB] << 8));
        }
    }


DoInterupts() is called at the end of each CPU cycle.

Is this the correct way to implement NMI and IRQ?


i think you only do this when the "I" register flag is unset.

Code:
-primary registers-
=register name ; desc=
A ; Accumulator
X ; Variable X
Y ; Variable Y

-flag registers-
=bit ; flag name ; desc=
7 ; N ; negative result
6 ; V ; result overflowed
5 ; - ; (unused)
4 ; B ; BRK instruction used
3 ; D ; decimal mode
2 ; I ; interrupt disabled
1 ; Z ; result zero
0 ; C ; carry occured


you seem to not be emulating the actual 8bit mask of the flags,
otherwise looks okay to me, but then again i am a newb to _nes_ emu.
Re: 6502 Interupts
by on (#37643)
Looks good to me except you should set the I flag on NMIs as well as IRQs.

Also... if you're doing this between cycles like you claim that might be a problem. IRQs/NMIs can only occur between CPU instructions. If you attempt an interrupt in the middle of an instruction you could end up borking something.
Re: 6502 Interupts
by on (#37669)
Disch wrote:
Looks good to me except you should set the I flag on NMIs as well as IRQs.

Also... if you're doing this between cycles like you claim that might be a problem. IRQs/NMIs can only occur between CPU instructions. If you attempt an interrupt in the middle of an instruction you could end up borking something.


that is why i suggest emulating the actual flags mask.

that way you refer to the mask between instructions, but edit the vars between cycles, and only refer to the mask to place into vars temporarily when emulating between instructions.
Re: 6502 Interupts
by on (#37735)
Not sure I follow what you mean.

by on (#37803)
You should listen to Disch. What he said is correct. The CPU doesn't check for interrupts until it's done executing the current opcode. You cannot interrupt an opcode.