6502 CPU emulator - Infinite loop running a NES game?

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
FlySwat
Posts: 5
Joined: Sun Sep 21, 2008 5:32 pm

6502 CPU emulator - Infinite loop running a NES game?

Post by FlySwat »

I had some free time this weekend, so I threw together a 6502 emulator, this is the first time I've ever looked at 6502, or written an emulator, so I'm sure there are lots of flaws.

Of course, I couldn't leave it at that, so I started researching the NES, and I wrote a rom file loaded.

Once a rom is loaded (Mario 1) and the instruction pointer pointed at the ROM bank, it gives the following output:
Program Counter Was At: 32768
Executing Instruction: Cpu6502.Opcodes.BRK with argument: 0
Program Counter Now At: 61569
Program Counter Was At: 61569
Executing Instruction: Cpu6502.Opcodes.LDX_A with argument: 1805
Program Counter Now At: 61572
Program Counter Was At: 61572
Executing Instruction: Cpu6502.Opcodes.CLC with argument: 0
Program Counter Now At: 61573
Program Counter Was At: 61573
Executing Instruction: Cpu6502.Opcodes.ADC_I with argument: 1
Program Counter Now At: 61575
Program Counter Was At: 61575
Executing Instruction: Cpu6502.Opcodes.DEC_ZP with argument: 0
Program Counter Now At: 61577
Program Counter Was At: 61577
Executing Instruction: Cpu6502.Opcodes.BCC with argument: -22270
Program Counter Now At: 39309
Program Counter Was At: 39309
Executing Instruction: Cpu6502.Opcodes.SBC_I with argument: 160
Program Counter Now At: 39311
Program Counter Was At: 39311
Executing Instruction: Cpu6502.Opcodes.BRK with argument: 0
Program Counter Now At: 61569
As you can tell, it immediately starts by hitting BRK, which jumps to $F081, it then runs a couple instructions before it hits a Branch If Carry which jumps back to $998D, the next instruction from that is another BRK, which causes the loop to repeat.

My question is, do I have a bug in BRK and BCC causing it to jump to the wrong addresses?

Is this normal behavior if I'm not handling something?

Full debug breakout for the emulator (All Registers and Flags) is available here:

http://pastebin.com/f4f3d680c

And the full source is available here:

http://www.codeplex.com/Cpu6502/SourceC ... SetId=1810

I'm hoping my CPU emulation is correct, and this is just what the NES would do if it is missing something in the implementation.

Thanks in advance.
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

I'm not sure if this is the same case, but anyway the CPU waits for an NMI to be triggered. Yeah, it's inside a loop.
FlySwat
Posts: 5
Joined: Sun Sep 21, 2008 5:32 pm

Post by FlySwat »

Fx3 wrote:I'm not sure if this is the same case, but anyway the CPU waits for an NMI to be triggered. Yeah, it's inside a loop.
NMI is triggered when the I flag in the P register is set correct?

If I look at my log dump, I see that both B and I are set all the time. When BRK fires, is it supposed to clear B?

Is there a document out there that explains how interrupts are triggered and handled in the 6502?
Roth
Posts: 400
Joined: Wed Aug 03, 2005 3:15 pm
Contact:

Post by Roth »

I'm no emu author, and judging by the fact that you are making a 6502 emulator you probably already know about this page, but it talks alot about interrupts:

http://6502.org/tutorials/interrupts.html

I don't know if that's helpful, but you never know : P
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

FlySwat wrote:NMI is triggered when the I flag in the P register is set correct?
The NMI is triggered when the PPU wants to, which is always when VBlank starts. NMI means "Non-Maskable Interrupt", meaning it is not masked by the I flag. NMIs will fire independently of this flag, as long as the PPU is configured to do it.

Depending on how much of the PPU you have implemented, games are likely to be stuck in loops (waiting for VBlank or an NMI).
FlySwat
Posts: 5
Joined: Sun Sep 21, 2008 5:32 pm

Post by FlySwat »

tokumaru wrote:
FlySwat wrote:NMI is triggered when the I flag in the P register is set correct?
The NMI is triggered when the PPU wants to, which is always when VBlank starts. NMI means "Non-Maskable Interrupt", meaning it is not masked by the I flag. NMIs will fire independently of this flag, as long as the PPU is configured to do it.

Depending on how much of the PPU you have implemented, games are likely to be stuck in loops (waiting for VBlank or an NMI).
In this case, I realize I need to be checking for interrupt after each instruction completes, how can I tell when a NMI is fired from the CPU state? When it does, I should push the Program Counter onto the stack and then point it at the interrupt vector correct?
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

FlySwat wrote:In this case, I realize I need to be checking for interrupt after each instruction completes, how can I tell when a NMI is fired from the CPU state?
As I said, the NMIs are generated by the PPU, so you must emulate it as well as the CPU. There are 262 scanlines in the video signal, out of those, 240 contain actual picture, 1 is a dummy, 20 are part of VBlank and 1 is a pre-render scanline. I guess you have to read about PPU timing in order to know the details, but each scanline lasts 341 PPU cycles, and VBlank happens every frame, so it will fire every 262 * 341 = 89342 PPU cycles. 1 CPU cycles is equivalent to 3 PPU cycles, so NMIs will happen roughly every 29780,6666... CPU cycles. But it's actually more detailed than that, you gotta read the timing docs. Anyway, everything I said is about the NTSC NES, things are quite different on PAL hardware.
When it does, I should push the Program Counter onto the stack and then point it at the interrupt vector correct?
You also have to push the status register.

Keep in mind that I'm no emulator programmer, I only make NES programs. I'm trying to help you with the knowledge I have of the system, which is not as deep as that of a good emulator programmer.
User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

Are you trying to run Super Mario Bros? I wouldn't recommend that for testing. You should try Donkey Kong. Not Donkey Kong Classics, just plain Donkey Kong. Or Donkey Kong Jr. They are good games for early emulator development. Or maybe Balloon Fight.

As tokumaru said, alot of games will eventually get stuck when they aren't getting what they want from NES registers you probably aren't emulating. Writing a 6502 CPU core is just the start. You need to implement the whole NES memory map, the registers, the PPU, etc. There isn't much point in just emulating the CPU as that's not going to make many games do much of anything. Also as it was said, NMI is triggered by the PPU at VBlank, while NMI executing alot of games just loop forever because they do pretty much everything in NMI.

Another thing, you should have your CPU logger or debugger show you values in HEX.
albailey
Posts: 177
Joined: Thu Jul 13, 2006 3:15 pm

Post by albailey »

In your code:
// Starting point where the code is
CPU.PC = 32767;


Is that the location of the reset Handler??

If not, you should refer to the last 6 bytes in the ROM. Those are 3 important addresses (IRQ, NMI and Reset. Probably not in that order).

Start running the program at the reset handler's address and see what happens.

I'm always suspicious of "BRK" commands

Edit- I checked. Super Mario's reset handler is 0x8000. Regular Mario Bros is 0xC000

Al
User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

If your code is as Al posted, that's dead wrong. Your CPU Reset should be something like, CPU.PC = GetWord(0xFFFC);

Because the reset vector is initialized by getting a Word (16bit) address location at address $FFFC. I Believe (though I didn't check) that the 6502 has it's 3 Interrupt vectors at FFFA,FFFC,and FFFE. And they are NMI, RESET, BRK/IRQ.

So when these interrupts happen, you fetch a word from these locations, this word is the "vector" the CPU.PC goes to for the interrupt. Reset doesn't do much, but BRK/IRQ and NMI will push certain values on the stack as they have to return.

Again, do yourself a favor and output your stuff in HEX values. It's much easier to understand that way.
FlySwat
Posts: 5
Joined: Sun Sep 21, 2008 5:32 pm

Post by FlySwat »

32767 = 0x7FFF, so I was one instruction off from the reset vector (32768 = 0x8000).

I started the Program Counter at the first rom bank in memory.

I'm well aware that the broken is looping because I don't have an outside source (PPU) triggering any interrupts.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

FlySwat wrote:32767 = 0x7FFF, so I was one instruction off from the reset vector (32768 = 0x8000).
Still, only some games have the reset code at $8000, so you can't hardcode your emulator to that location. The actual location of the reset code is always indicated by the values at $FFFC and $FFFD.
User avatar
MottZilla
Posts: 2835
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

You also may want to know that in games like Donkey Kong or Mario Bros that only have "1 rom bank" or are 16K in PRG size, that same 16K will appear at $8000 and $C000. That means that the reset Vector will appear at $FFFC.

Also sorry if I sounded harsh. Just trying to help you out.
Post Reply