It is currently Tue Nov 21, 2017 5:03 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Thu Jan 17, 2013 3:09 pm 
Offline

Joined: Sun Jan 13, 2013 5:35 pm
Posts: 23
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:
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!


Top
 Profile  
 
PostPosted: Thu Jan 17, 2013 4:00 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
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.


Top
 Profile  
 
PostPosted: Thu Jan 17, 2013 4:04 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19237
Location: NE Indiana, USA (NTSC)
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.


Top
 Profile  
 
PostPosted: Thu Jan 17, 2013 5:05 pm 
Offline

Joined: Sun Jan 13, 2013 5:35 pm
Posts: 23
Thanks a lot guys!!!! :) It works fine now!

It broke up here:

Code:
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...


Top
 Profile  
 
PostPosted: Thu Jan 17, 2013 8:18 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
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.


Top
 Profile  
 
PostPosted: Fri Jan 18, 2013 3:22 am 
Offline

Joined: Sun Jan 13, 2013 5:35 pm
Posts: 23
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! :)


Top
 Profile  
 
PostPosted: Fri Jan 18, 2013 6:05 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19237
Location: NE Indiana, USA (NTSC)
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)?


Top
 Profile  
 
PostPosted: Fri Jan 18, 2013 6:36 am 
Offline

Joined: Sun Jan 13, 2013 5:35 pm
Posts: 23
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!


Top
 Profile  
 
PostPosted: Fri Jan 18, 2013 6:39 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19237
Location: NE Indiana, USA (NTSC)
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.


Top
 Profile  
 
PostPosted: Fri Jan 18, 2013 8:02 am 
Offline

Joined: Sun Jan 13, 2013 5:35 pm
Posts: 23
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.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group