It is currently Mon Apr 24, 2017 8:15 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Wed Feb 15, 2017 6:55 pm 
Offline

Joined: Wed Feb 15, 2017 6:41 pm
Posts: 8
I'm writing a NES emulator and the CPU is fully implemented, and I'm currently implementing memory mapping to all the other components (PPU, APU, etc), initially only mapping with NROM in mind. I'm not at the point where I'm actually drawing pixels, but I'm able to load and execute NES roms, and it's actually getting past PPU initialization.

The ROM I've been loading is Mario Bros. (not Super Mario Bros, the original 1983 Mario Bros) and my emulator kept crashing because it was encountering an unexpected opcode. My initial thought was that my opcode decoding was wrong, so I booted up FCEUX and looked at the PRG in its debugger. Lo-and-behold, there are undefined opcodes scattered throughout:

Image

My emulator is crashing at offset $8511 specifically ($d3 is the value). What's the deal with this? Would a fully implemented emulator just never attempt to execute this bogus instruction?


Top
 Profile  
 
PostPosted: Wed Feb 15, 2017 7:00 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5032
Location: Canada
I don't think that opcode is the real problem here. Mario Bros.' code is built to run only in the $C000-FFFF region. If you're PC has ended up in $8000-BFFF something else has already gone wrong and you're executing from the wrong location, I think. $8511 should be unreachable.

$D3 is an illegal opcode, but it does have a specific function on the 6502/2A03 that you can (and probably should) implement in your emulator, but the game in question does not rely on any illegal opcodes to function.


Top
 Profile  
 
PostPosted: Wed Feb 15, 2017 7:04 pm 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 18183
Location: NE Indiana, USA (NTSC)
Try stepping into JSR $CD9E. That routine probably handles a jump table, taking a value in A and using it as an index into a table of function pointers that follow the JSR, not unlike a switch statement in C. Games may use a jump table to call update routines for each game state based on the state ID, movement routines for each enemy based on the enemy type, etc. Super Mario Bros. has something similar, called magic_jmp or JumpEngine depending on which disassembly you're looking at, as does the FDS BIOS at $EAFD.

If my guess is correct, the function addresses are $D34A, $E14A, $D3F9, $D3A8, ... which look normal for an NROM-128 game like this. If execution goes off into the weeds after a JSR $CD9E, your JSR or RTS might be wrong.


Top
 Profile  
 
PostPosted: Wed Feb 15, 2017 7:29 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 9519
Location: Rio de Janeiro - Brazil
This is a real-time disassembly that starts from the address at the top of the window and doesn't discern code from data. This means that if the top of the window isn't properly aligned to an instruction, it might disassemble things the wrong way, and if it runs into data, it will certainly disassemble garbage.


Top
 Profile  
 
PostPosted: Wed Feb 15, 2017 9:43 pm 
Offline
User avatar

Joined: Wed Oct 16, 2013 7:55 am
Posts: 104
Never mind the alignment, I don't think this part of ROM is even being executed as code, according to this FCEUX screenshot. The PC isn't in the $8000 range, and there's no breakpoint visible.


Top
 Profile  
 
PostPosted: Wed Feb 15, 2017 9:59 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5032
Location: Canada
OP was using FCEUX to look at a disassembly of the region where their emulator had crashed, trying to figure out what was going wrong. It's not FCEUX that tried to execute from $8511. I don't think the disassembly is really an issue here.

Tepples' explanation of the jump table subroutine is correct; that's exactly what the code at $CD9E does. Without knowing about that kind of thing, perhaps OP was presuming that the bytes after that JSR might be run as code (but they will not).

I can't speculate where the real problem is, though. I'd suggest tracing execution until the PC moves into $8000-BFFF. The problem is going to be before that, since it shouldn't be running in that region at all for this ROM.


Top
 Profile  
 
PostPosted: Thu Feb 16, 2017 9:32 am 
Offline

Joined: Wed Feb 15, 2017 6:41 pm
Posts: 8
Thanks for the replies everyone, I have to digest some of this but it's mostly making sense.

One thing I'm clearly doing wrong in my emulator is starting execution with PC = 0x8000, where instead it should start at 0xC000. Am in incorrect in believing that this should be mostly equivalent, though? For NROM in particular, isn't the address space starting at 0x8000 a mirror of 0xC000? Following up on this, for any particular game, how do we know which offset to being execution at? Is it mapper specific?

Thanks again for all the responses.


Top
 Profile  
 
PostPosted: Thu Feb 16, 2017 9:42 am 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 18183
Location: NE Indiana, USA (NTSC)
When a 6502 CPU comes out of reset, it begins execution at the address stored at $FFFC and $FFFD.

  • If these bytes are 00 80, execution starts at $8000.
  • If these bytes are 00 C0, execution starts at $C000.
  • Otherwise, execution doesn't start at $8000 or $C000.

Treating a reset as JMP ($FFFC) will handle 99.9 percent of cases correctly.


Top
 Profile  
 
PostPosted: Thu Feb 16, 2017 10:02 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5032
Location: Canada
wbrian wrote:
One thing I'm clearly doing wrong in my emulator is starting execution with PC = 0x8000, where instead it should start at 0xC000. Am in incorrect in believing that this should be mostly equivalent, though? For NROM in particular, isn't the address space starting at 0x8000 a mirror of 0xC000? Following up on this, for any particular game, how do we know which offset to being execution at? Is it mapper specific?


NROM-128 (16k) mirrors data at $8000 and $C000, but I think the canonical position of the code is $C000, mostly because the ROM already has to include the vector table at $FFFA.

What ROM data is mapped to which ranges is mapper specific, but reset will always start from the position specified at $FFFC regardless of mapper.

Now, the game in question does have identical data at $8000 and $C000, and $FFFC does in fact point to $C000. You are correct to believe that it's "mostly" equivalent in this case. For this particular ROM, I don't see any problems caused by starting at $8000 instead in FCEUX. There are potential differences from starting at a mirrored code address, but I don't believe they affect this game.

So, even though you had not been using the reset vector, it's not actually what caused the problem for you. Maybe tepples' suggestion to look at the subroutine at $CD9E would help? Perhaps you haven't implemented JMP (indirect) correctly, or maybe you store an off-by-one return address on the stack, instead of incrementing it after RTS?


Top
 Profile  
 
PostPosted: Thu Feb 16, 2017 12:22 pm 
Offline
User avatar

Joined: Sun May 27, 2012 8:43 pm
Posts: 1210
wbrian wrote:
Thanks for the replies everyone, I have to digest some of this but it's mostly making sense.

One thing I'm clearly doing wrong in my emulator is starting execution with PC = 0x8000, where instead it should start at 0xC000. Am in incorrect in believing that this should be mostly equivalent, though? For NROM in particular, isn't the address space starting at 0x8000 a mirror of 0xC000? Following up on this, for any particular game, how do we know which offset to being execution at? Is it mapper specific?

Thanks again for all the responses.


In short, $FFFC contains a two-byte pointer to the reset vector, the entry point. This is stored in the native little-endian format.


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: Bing [Bot], Google Adsense [Bot] 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