Branches and wrap-arounds problem?

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
miguelfsp
Posts: 23
Joined: Sun Jan 13, 2013 5:35 pm

Branches and wrap-arounds problem?

Post by miguelfsp »

Hey guys, I currently have my 6502 emulator passing all the nestest tests without any errors.

However, when I was fixing bugs I came across a problem with one of the BNE instructions in nestest. I figured out what was happening: When I was "jumping" I was adding the immediate directly to the program counter (PC += immediateByte).

I realized that it was wrong because the highest significant bit would wrap-around, so I fixed the bug this way:

Code: Select all

this.PC = (UInt16)((this.PC & 0xFF00) | ((this.PC + immediateByte) & 0xFF));
And after that it worked all right... So I replicated that line in all the other Branches and removed the old (PC+=immediateByte) code.

But when I do this to all the other branches, nestest starts failing. :/ So I kept it only at the BNE. Today I loaded another NES ROM and it was also messing up with the jumps, so I also replaced the BPL to do the wrap-around.

Now, obvisouly there is something REALLY wrong here. :/ Do you guys have any ideas? Am I missing something about the branch instructions? Oh by the way, when I say "PC" I mean the PC at the beggining of the instruction.

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

Re: Branches and wrap-arounds problem?

Post by blargg »

I'm surprised your emulator passed all the CPU tests, as I'm sure there's one that catches this bug. You should simply be adding the operand byte interpreted as a signed 8-bit value. Since a (two's complement) byte simply has a negative weight for the top bit (-128), you can portably convert an unsigned to signed with (n^0x80)-0x80.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Branches and wrap-arounds problem?

Post by tepples »

For a taken branch, you need to compute both the address that you'd get from 16-bit addition to the sign-extended value and the address that you'd get from 8-bit wraparound. If the two addresses match, the branch is 3 cycles; otherwise, it's 4 cycles, with one of the cycles being an unused fetch from the 8-bit wraparound address. (Not taken branches are always 2 cycles.) Either way, execution resumes at the address resulting from 16-bit addition.
miguelfsp
Posts: 23
Joined: Sun Jan 13, 2013 5:35 pm

Re: Branches and wrap-arounds problem?

Post by miguelfsp »

Thanks a lot guys!!!! :) It works fine now!

It broke up here:

Code: Select all

C729  CA        DEX                             A:CB X:05 Y:4F P:6D SP:F1 CYC:276 SL:108
C72A  D0 E0     BNE $C70C                       A:CB X:04 Y:4F P:6D SP:F1 CYC:282 SL:108
C70C  68        PLA                             A:CB X:04 Y:4F P:6D SP:F1 CYC:291 SL:108
But somehow... my wrap-around solution "fixed" the issue and passed the test. Still can't really understand how, but ok...
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Branches and wrap-arounds problem?

Post by blargg »

If you were branching to the wrong place sometimes, it would have been easy for those wrong branches to produce no noticeable effects even though they were messing something up. At the very least, they were probably skipping some tests.
miguelfsp
Posts: 23
Joined: Sun Jan 13, 2013 5:35 pm

Re: Branches and wrap-arounds problem?

Post by miguelfsp »

Yes, but somehow, that didn't happen and it would jump to the right line... which is odd, probably just "coincidence".

You see, I created my own "test function". I made a function to parse nestest.log that generates a similar file containing only the registers in each line (removing scanlines, disasm, etc), so I compare nestest log line by line with the output of my cpu. When the strings are different, I output them both, and the line number in nestest.log. I could reach the end, even with that bug.

Still no PPU, though. Also haven't tested the instructions timing yet.

Thanks again! :)
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Branches and wrap-arounds problem?

Post by tepples »

So at each line you compared program counter and AXYPS. That's similar to what I did. When you removed scanlines, did you keep the CYC (which refers to dots, where 3 dots = 1 CPU cycle)?
miguelfsp
Posts: 23
Joined: Sun Jan 13, 2013 5:35 pm

Re: Branches and wrap-arounds problem?

Post by miguelfsp »

Yep, I removed CYC. I know I have some bugs in timing though. Actually I'm working at it right now.

By the way, I still don't know much about the PPU - when you say "dots", what do you mean exacly in terms of PPU functionality?

Thanks!
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Branches and wrap-arounds problem?

Post by tepples »

Assuming Famicom, NTSC NES, or PlayChoice:

First see blargg's post about clocks, pixels, and cycles. The PPU produces a new pixel, or dot, every four master clocks. One CPU cycle is twelve master clocks. CYC in the nestest log counts dots. So every time CYC increases by three, the CPU performs one cycle of work.
miguelfsp
Posts: 23
Joined: Sun Jan 13, 2013 5:35 pm

Re: Branches and wrap-arounds problem?

Post by miguelfsp »

Thank you very much! :) I think I got the cycles working great now. I'll check that link later today. Now heading off to a "pleasant" exam in college.
Post Reply