Debugging the cpu core

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
Movax12
Posts: 529
Joined: Sun Jan 02, 2011 11:50 am

Re: Debugging the cpu core

Post by Movax12 »

blargg wrote:Nintendulator's log doesn't even make sense, or it's lying about the value read from $2002.
I believe this explains the $FF values:
NES Stuff by Quietust wrote:I suspect some confusion may have arisen from the fact that Nintendulator's debugger displays values of $FF within ExRAM even while executing - this is not what the CPU is actually executing, but it is what the debugger shows whenever it is viewing a region of memory it believes to contain I/O registers..
http://www.qmtpro.com/~nes/
User avatar
Dartht33bagger
Posts: 59
Joined: Sat Jan 03, 2009 3:28 pm
Location: Oregon
Contact:

Re: Debugging the cpu core

Post by Dartht33bagger »

blargg wrote:Nintendulator's log doesn't even make sense, or it's lying about the value read from $2002.
Exactly. I have no idea what how it's getting those results since they look nothing like what I'm expecting.
NES Stuff by Quietust wrote:I suspect some confusion may have arisen from the fact that Nintendulator's debugger displays values of $FF within ExRAM even while executing - this is not what the CPU is actually executing, but it is what the debugger shows whenever it is viewing a region of memory it believes to contain I/O registers..
Well that's great. So there is no way to know what nestendulator is actually doing.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Debugging the cpu core

Post by blargg »

It'd be better to make a log of the core CPU test that doesn't do any PPU stuff. It has a different starting address.

Hmmm, I see that the one mentioned on the wiki does just this, and has no $2002 reads in the log. This is the way to go.
Grapeshot
Posts: 85
Joined: Thu Apr 14, 2011 9:27 pm
Contact:

Re: Debugging the cpu core

Post by Grapeshot »

$2002 is a read only PPU register and reading it has some effects on the PPU, which is why Nintendulator's debugger doesn't display it correctly, because reading it from the debugger might cause side effects and there is no extra read-with-no-side-effects function for the debugger to use.

If the tests are looping on $2002 that would indicate that the test is done and it's trying to print the results of the test to the PPU. I'm not sure how that is happening if you don't see any output written at $6000 since that should happen first.

edit: actually I went ahead and made a log of test 03 to compare with what you are seeing, and it looks like the test is checking for the existence of a PPU by looping for a few frames and seeing if that flag ever changes. You can ignore differences with Nintendulator on that part of the test and move on to line 27,000 or so of the log. (See why I said you needed a robust diff tool to analyze these?)

The place where you were actually failing the test is around line 35,000 where this block of code is executed:

Code: Select all

E373 A0 LDY #$07        PC:E374 A:BF X:8C Y:00 P:27 SP:9C CYC:109 SL:244
E375 84 STY $29         PC:E376 A:BF X:8C Y:07 P:25 SP:9C CYC:115 SL:244
E377 B9 LDA $E222,y     PC:E378 A:BF X:8C Y:07 P:25 SP:9C CYC:124 SL:244
E37A 8D STA $03A1       PC:E37B A:FF X:8C Y:07 P:A5 SP:9C CYC:136 SL:244
E37D A6 LDX $21         PC:E37E A:FF X:8C Y:07 P:A5 SP:9C CYC:148 SL:244
E37F 9A TXS             PC:E380 A:FF X:90 Y:07 P:A5 SP:9C CYC:157 SL:244
E380 B9 LDA $E222,y     PC:E381 A:FF X:90 Y:07 P:A5 SP:90 CYC:163 SL:244
E383 8D STA $03A1       PC:E384 A:FF X:90 Y:07 P:A5 SP:90 CYC:175 SL:244
E386 A5 LDA $1D         PC:E387 A:FF X:90 Y:07 P:A5 SP:90 CYC:187 SL:244
E388 48 PHA             PC:E389 A:00 X:90 Y:07 P:27 SP:90 CYC:196 SL:244
E389 A5 LDA $1E         PC:E38A A:00 X:90 Y:07 P:27 SP:8F CYC:205 SL:244
E38B A6 LDX $1F         PC:E38C A:FF X:90 Y:07 P:A5 SP:8F CYC:214 SL:244
E38D A4 LDY $20         PC:E38E A:FF X:00 Y:07 P:27 SP:8F CYC:223 SL:244
E38F 28 PLP             PC:E390 A:FF X:00 Y:01 P:25 SP:8F CYC:232 SL:244
E390 4C JMP $03A0       PC:E391 A:FF X:00 Y:01 P:20 SP:90 CYC:244 SL:244
03A0 A9 LDA #$FF        PC:03A1 A:FF X:00 Y:01 P:20 SP:90 CYC:253 SL:244
03A2 4C JMP $E393       PC:03A3 A:FF X:00 Y:01 P:A0 SP:90 CYC:259 SL:244
E393 08 PHP             PC:E394 A:FF X:00 Y:01 P:A0 SP:90 CYC:268 SL:244
Basically what's going on here is that the test is copying some data to RAM that was generated previously in the test, and then jumping to its location. The data itself happens to be a jump to the next portion of the test. So either your CPU can't execute code from RAM, or the wrong data is being copied to this location at some point, which could be caused by a bug thousands of lines previously in the log.
User avatar
Dartht33bagger
Posts: 59
Joined: Sat Jan 03, 2009 3:28 pm
Location: Oregon
Contact:

Re: Debugging the cpu core

Post by Dartht33bagger »

blargg wrote:It'd be better to make a log of the core CPU test that doesn't do any PPU stuff. It has a different starting address.

Hmmm, I see that the one mentioned on the wiki does just this, and has no $2002 reads in the log. This is the way to go.
My cpu passes that test up until the illegal opcodes come in. Once those start, if I have my illegal opcodes turned off, the PC counter gets off once the first illegal opcode shows up. If I have my illegal opcodes turned on, I pass up until I get to DCP instruction and then I couldn't figure out what Nintendulator was doing with the processor flags (I didn't know what I was comparing). At that point I was told to go to your tests since the illegal opcodes would just print out as a wrong so I could focus on the official opcodes.

As for grapeshot: my core does fail in that $2002 loop. A BMI instruction breaks out of the loop in Nintendulator that mine never does, so the PC is always off from that line on in the debugging file.
Grapeshot
Posts: 85
Joined: Thu Apr 14, 2011 9:27 pm
Contact:

Re: Debugging the cpu core

Post by Grapeshot »

Like I said, it's breaking out of the loop because the PPU sets the VBlank flag in the $2002 register. It has nothing to do with the correctness of your CPU code, you just haven't emulated any of the PPU yet. Maybe try to get the PPU registers working properly and write some code to display the nametable, and try to run Balloon Fight.
User avatar
Dartht33bagger
Posts: 59
Joined: Sat Jan 03, 2009 3:28 pm
Location: Oregon
Contact:

Re: Debugging the cpu core

Post by Dartht33bagger »

I'll mess with that tomorrow I suppose. I have a PPU written that has code for displaying nametables, but it doesn't work nearly as well as I'd hoped. When a test passes, I just get a solid white line down down the right side of the screen. Donkey Kong used to display a bunch of light blue rectangle all over the screen, but it doesn't do that anymore. I was hoping to get the CPU 100% nailed down before I try to figure out why the PPU doesn't work right for the 50th time.
User avatar
Dartht33bagger
Posts: 59
Joined: Sat Jan 03, 2009 3:28 pm
Location: Oregon
Contact:

Re: Debugging the cpu core

Post by Dartht33bagger »

Well Grapeshot, you were right. The ppu timing is off just enough that I'm not passing the BIT tests when I need to. Time to figure out why my ppu timing isn't right like I had thought it was.

Edit: I'm happy to report that I do get output now on 03-immedaite. I'm missing the illegal opcodes but none of the official opcodes. Unfortunately, my PPU still doesn't set the vblank bit at the right time, so I'm getting a segmentation error since the PC gets off. I'll work on that more tomorrow.
User avatar
Dartht33bagger
Posts: 59
Joined: Sat Jan 03, 2009 3:28 pm
Location: Oregon
Contact:

Re: Debugging the cpu core

Post by Dartht33bagger »

Almost no progress to report this week. I spent a lot of time trying to figure out some financial problems that I had for school, so I didn't really work on this at all. I'm starting school again a week, so I doubt I'll get this thing running anything before then. I'll be taking systems programming fall term, so maybe that will help me when I come back to this project over winter break.

Edit: Worked on the core tonight and got the nestest to pass. No errors at all. I still can't pass blarg's tests because of PPU timing. The vblank flag somehow isn't being set on the right cycle, so I'll be working on that this week.
User avatar
Dartht33bagger
Posts: 59
Joined: Sat Jan 03, 2009 3:28 pm
Location: Oregon
Contact:

Re: Debugging the cpu core

Post by Dartht33bagger »

For some reason my BRK instruction is not working correctly. I can't for the life of me figure out why. For some reason, the PC just goes to some crazy wrong value. What am I doing wrong?

Code: Select all

case 0x00:	//BRK
			data = ((PC & 0xFF00) >> 8);		//Push high byte first
			pushStack(memory, data, ppu);
			data = PC & 0xFF;
			pushStack(memory, data, ppu);	
			//Bit-----7--6--5--4--3--2--1--0 PHP always has B and bit 5 true
			//Order = N, V, 1, B, D, I, Z, C
			statusFlags[0] = C, statusFlags[1] = Z, statusFlags[2] = I, statusFlags[3] = D,
			statusFlags[4] = 1, statusFlags[5] = 1, statusFlags[6] = V, statusFlags[7] = N;
			statusByte = encodeBits(statusFlags);	//Puts the status flags into a
			pushStack(memory, statusByte, ppu);				//byte	
			PC = (memory->readRAM(0xFFFF, ppu) << 8);
			PC += memory->readRAM(0xFFFE, ppu);
			I = true;
			debugImplied(ppu, opcode, "BRK");
			cycles = cycleCount[opcode];
			break;
User avatar
James
Posts: 429
Joined: Sat Jan 22, 2005 8:51 am
Location: Chicago, IL
Contact:

Re: Debugging the cpu core

Post by James »

Try adding 1 to the PC before pushing it onto the stack.
get nemulator
http://nemulator.com
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Debugging the cpu core

Post by koitsu »

Per official WDC documentation (pay close attention to the very first and last lines):
The program counter is incremented by two, then pushed onto the stack; the status register, with the b break flag set, is pushed onto the stack; the interrupt disable flag is set; and the program counter is loaded from the interrupt vector at $FFFE-FFFF. It is up to the interrupt handling routine at this address to check the b flag in the stacked status register to determine if the interrupt was caused by a software interrupt (BRK) or by a hardware IRQ, which shares BRK vector but pushes the status register onto the stack with the b break flag clear.
...
BRK is 1 byte, but program counter value pushed onto stack is incremented by 2 allowing for optional signature byte.
I should note the "signature byte" is not really "optional" despite how this is worded. Assemblers/disassemblers which simply print "BRK" (rather than BRK $xx) are quite simply wrong. :-)

Regarding the flags which are set that are pushed onto the stack, this has been discussed on the forum before, and I even verified using an actual 65816 (in 65c02 emulation mode (the behaviour here is the same as 6502)) and made a video:

viewtopic.php?f=3&t=6597 (READ THE ENTIRE THREAD, DO NOT SKIM IT)
http://www.youtube.com/watch?v=1BWJ2vDr8v8

You're welcome.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Debugging the cpu core

Post by blargg »

koitsu wrote:I should note the "signature byte" is not really "optional" despite how this is worded. Assemblers/disassemblers which simply print "BRK" (rather than BRK $xx) are quite simply wrong. :-)
It depends on what the BRK handler does. My understanding is that BRK was often used for debugging or to patch ROMs, so that the BRK handler never merely executed an RTI when it was done, rather it checked a table of patches based on the address. If one used BRK in source code, one might have the handler decrement the return address so that it became a one-byte instruction. Or one could do a PLP then RTS to have it become a three-byte instruction.
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Debugging the cpu core

Post by koitsu »

Regardless of the BRK handler, PC+2 is still pushed onto the stack by the processor. What the BRK handler wants to do after its called is purely up to the author of the 6502 code itself; but the processor still pushes PC+2 for that "signature byte".

This is even covered in the 6502 Programming Manual -- see page 145 (or page 156 in the PDF itself), 2nd paragraph (gotta read the whole thing). The same document mentions how BRK can be used to patch/tinker with existing code (page 144 (page 155 in PDF)). However, the example code given on page 145 is incorrect/wrong (it says "BRK 00" when it should just say "BRK" (or more accurately, "BRK 05" for $FC21, then proceed onward with $FC23)).

It's pretty remarkable how often this gets mucked up, simply because not a lot of people bother to use BRK.

I should note I would not be surprised if there were some 6502 CPUs out there (somewhere) which really did do PC+1 instead and did not support the "signature byte", but at least in the case of the NES/FC (and the Apple II series) the processor pushes PC+2.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Debugging the cpu core

Post by blargg »

I hadn't realized that people's emulators/disassemblers handled it wrong (looks like my disassembler shows the byte: "BRK #n").

Pushing PC+1 would actually be the better behavior for all uses. When used as a syscall with the second byte the selector, the handler could just pop the return address and examine the byte there to get the selector (rather than having to decrement it), and when returning, do PLP; RTS to skip the selector byte without any mucking around.
Post Reply