Passing blargg's 10-stack.nes test

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
LightStruk
Posts: 45
Joined: Sat May 04, 2013 6:44 am

Passing blargg's 10-stack.nes test

Post by LightStruk » Sat May 04, 2013 8:52 am

I've been scratching my head over how my emulator can completely pass all of blargg's nes_instr_test ROMs except for the stack test ROM. The message at $6004 says

Code: Select all

08 PHP
68 PLA
28 PLP
9A TXS
BA TSX

10-stack

Failed
My emulator also produces output on nestest.nes identical to the "golden" Nintendulator log (ignoring the cycle count and scanline columns, which my emulator doesn't output yet.) In other words, the stack pointer and processor status registers are both verified correct, at least with nestest.

Adding to my confusion - these five instructions are REALLY simple. If these fundamental instructions were broken, how could my emulator do so well on the other CPU tests?

User avatar
ulfalizer
Posts: 349
Joined: Fri Mar 08, 2013 9:55 pm
Location: Linköping, Sweden

Re: Passing blargg's 10-stack.nes test

Post by ulfalizer » Sat May 04, 2013 8:59 am

Wild guess, but are you handling wrap-around properly so that you always stay within the stack page?

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Passing blargg's 10-stack.nes test

Post by blargg » Sat May 04, 2013 9:24 am

PHA wasn't flagged, so I'm guessing that your processor has 8 status bits in the P register, rather than only 6 as is correct. :)

PLA was, so maybe wrapping is wrong, or you aren't setting status flags correctly.

Failing TSX is probably not setting the Z and N flags based on what's put into X. I can only assume the same for TXS, which doesn't change any flags.

User avatar
LightStruk
Posts: 45
Joined: Sat May 04, 2013 6:44 am

Re: Passing blargg's 10-stack.nes test

Post by LightStruk » Sat May 04, 2013 10:45 am

Thank you for helping me investigate this!

With regard to wrapping, I use a uint8_t to store the stack pointer, which I post-decrement on Push and pre-increment on Pop:

Code: Select all

inline void CPU::PushStack(uint8_t value)
{
	Write(value, STACK + Registers.sp);
	--Registers.sp;
}

inline uint8_t CPU::PopStack()
{
	++Registers.sp;
	return Read(STACK + Registers.sp);
}

I use an 8-bit byte to store the processor status, but I try to be careful to ensure that there are only six real flags.
My implementation of PLP looks like this:

Code: Select all

// dummy read of top of stack
Read(STACK + Registers.sp);
Registers.p.raw = (PopStack() | 0x20) & 0xEF; // bit 5 is always 1, b is set back to 0
TSX:

Code: Select all

Registers.x = Registers.sp;
Registers.p.n = (Registers.x >= 0x80);
Registers.p.z = (Registers.x == 0);
TXS:

Code: Select all

Registers.sp = Registers.x;

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Passing blargg's 10-stack.nes test

Post by blargg » Sat May 04, 2013 4:18 pm

How about your PHP?

User avatar
LightStruk
Posts: 45
Joined: Sat May 04, 2013 6:44 am

Re: Passing blargg's 10-stack.nes test

Post by LightStruk » Sat May 04, 2013 7:03 pm

PHP:

Code: Select all

PushStack(Registers.p.raw | 0x10); // PHP pushes the flags with b set to 1

User avatar
LightStruk
Posts: 45
Joined: Sat May 04, 2013 6:44 am

Re: Passing blargg's 10-stack.nes test

Post by LightStruk » Sat May 04, 2013 7:10 pm

One more thing - I downloaded instr_test-v3 today, and despite passing everything in nes_instr_test except test 10, I get failures all OVER the place with instr_test-v3. Not every instruction, but many of them. For example, the failures for tests 1 and 2:

instr_test-v3/rom_singles/01-implied.nes:
0A ASL A, 8A TXA, AA TAX, C8 INY, 88 DEY, 38 SEC, 18 CLC, F8 SED, 78 SEI, 58 CLI, 5A NOP
instr_test-v3/rom_singles/02-immediate.nes:
A2 LDX #n, E0 CPX #n, 82 DOP #n, 89 DOP #n, C2 DOP #n, E2 DOP #n, CB AXS #n

I failed NOP (opcode 0x5A)? How did I fail that NOP and not the other six versions of NOP? And in 02-immediate, I fail 4 DOPs, but not the fifth DOP (opcode 0x80)?

Even though my PPU is not done yet, is there anything I need do for reads from $2002, $2004, or $2007 to make the tests happy?

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Passing blargg's 10-stack.nes test

Post by blargg » Sat May 04, 2013 7:51 pm

Probably something systemic. Is your emulator generating any interrupts during the tests? That would modify the stack and cause failure. NMI and /IRQ should not be occurring during the tests.

The tests shouldn't rely on anything from the PPU. At the most, they might need $2002 to wait for VBL, but the symptom of that would be a hang, not a failure. Later versions don't require a PPU at all (I'm pretty sure I got that released).

User avatar
LightStruk
Posts: 45
Joined: Sat May 04, 2013 6:44 am

Re: Passing blargg's 10-stack.nes test

Post by LightStruk » Sat May 04, 2013 8:56 pm

That was it - I was generating NMIs when I should not have been. My half-baked PPU logic was worse than no PPU at all. :D Now my emulator passes all of your instr_tests!

Thank you so much for your help!

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Passing blargg's 10-stack.nes test

Post by blargg » Sat May 04, 2013 9:21 pm

Glad you finally passed! I swear I had a version that checked for unwanted interrupts, since I think this happened to someone a few years back. Now that I've been working on NES stuff again, I'll have to do an update.

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Passing blargg's 10-stack.nes test

Post by blargg » Sun May 05, 2013 6:57 am

OK, updated instruction test that reports unexpected interrupts instead of random failing tests (added to Wiki too): instr_test-v4.zip

Turns out I had written this improvement, but never been able to build and release it a few years ago.

Post Reply