6502 Interupts

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
FlySwat
Posts: 5
Joined: Sun Sep 21, 2008 5:32 pm

6502 Interupts

Post by FlySwat »

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: Select all

    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?
User avatar
jargon
B&: This is not your blog
Posts: 208
Joined: Fri Dec 07, 2007 11:40 pm
Location: 480/85260
Contact:

Re: 6502 Interupts

Post by jargon »

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: Select all

    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: Select all

-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.
Cheers,
Timothy Robert Keal alias jargon

Image
Miser's House Anthology Project
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Re: 6502 Interupts

Post by Disch »

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.
User avatar
jargon
B&: This is not your blog
Posts: 208
Joined: Fri Dec 07, 2007 11:40 pm
Location: 480/85260
Contact:

Re: 6502 Interupts

Post by jargon »

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.
Cheers,
Timothy Robert Keal alias jargon

Image
Miser's House Anthology Project
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Re: 6502 Interupts

Post by Disch »

Not sure I follow what you mean.
User avatar
MottZilla
Posts: 2837
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

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.
Post Reply