weird stack bug

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
sahib
Posts: 26
Joined: Fri Jan 08, 2010 10:41 pm
Location: peninsular scandinavia

weird stack bug

Post by sahib » Fri Jan 08, 2010 11:01 pm

First off, this forum has been a tremendous help for me when developing the first three iterations of my emulator.

However, I've run into a little difficulty, and I was hoping that somebody here might have an idea/suggestion that could point me in the right direction.

I recently rewrote my CPU emulation core and I've come across a bug which is giving me a headache (or migraine, rather).

Whenever the CPU is about to RTI from a NMI, it pops the wrong return adress from the stack and jumps into oblivion. I've tracked down the issue to that the stackpointer isn't incremented/decremented as it should be, or rather, there is one push more than there are pops before RTI.

The only game out of my test roms I've found that this bug doesn't affect is SMB, which runs properly.

If I add another POP to my RTI-implementation, many other roms loads and runs without issues, such as donkey kong, pac-man and mario brothers, but alas, it breaks super mario bros.

Does anybody have any idea what I'm doing wrong?

Please don't flame me too hard if I have overlooked something obvious, this is my first post after all :-)

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Fri Jan 08, 2010 11:10 pm

If I'm reading your post right, you already found the problem.

Look at your NMI code -- count the number of stack pushes. There should be 3

Look at your RTI code -- count the number of stack pops. There should be 3.

Make sure the push/pops are in the right order:

push high PC
push low PC
push status

pop status
pop low PC
pop high PC

Or you could post your NMI/RTI code here and maybe we can spot it.

User avatar
sahib
Posts: 26
Joined: Fri Jan 08, 2010 10:41 pm
Location: peninsular scandinavia

Post by sahib » Fri Jan 08, 2010 11:16 pm

NMI:

Code: Select all

NMI()
{
	
                PUSH(MSB(PC)); //push PC to stack
                PUSH(LSB(PC)); //

                PUSH(flags.SR); //push status register
                PC = MAKE_WORD(memory->ReadMemory(0xFFFA), memory->ReadMemory(0xFFFB));
                

            
                ppu.NMI_occured = true;
		
                flags.members.I = 1; 
		branch = true;

}

Code: Select all

RTI()
{	
flags.SR = POP();
		
		byte msb, lsb;
		lsb = POP();//lsb
		msb = POP();//msb

		PC = MAKE_WORD(lsb, msb);

		ppu.NMI_occured = false;
	//	PrintDebug("RTId @ $%04X", PC);
		branch = true;
}

User avatar
Disch
Posts: 1849
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch » Fri Jan 08, 2010 11:53 pm

Looks fine to me.
I've tracked down the issue to that the stackpointer isn't incremented/decremented as it should be, or rather, there is one push more than there are pops before RTI.
I might've misunderstood this sentence before. Maybe SP is getting screwed up somewhere between NMI and RTI.

Do you have a CPU tracer? I recommdend writing one. Not only to solve this problem, but to solve all future problems (not just CPU related -- a CPU tracer is key in solving any emulation bug)

If you make a trace of all the instructions the CPU is executing and the state of the registers (specifically, SP), you will easiliy be able to spot where SP is getting screwed up.

User avatar
sahib
Posts: 26
Joined: Fri Jan 08, 2010 10:41 pm
Location: peninsular scandinavia

Post by sahib » Sat Jan 09, 2010 1:14 pm

edit:

eventually found the bug. When NMI occured I didn't didn't increment the PC accordingly, so the first instruction (PHA) executed twice, thus fuxx0ring the SP. a nights' sleep can really do wonders for code-weary eyes :-)

cheers disch!

Post Reply