My cart runs differently in different emulators

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

My cart runs differently in different emulators

Post by puppydrum64 »

My test cartridge is pretty simple. It plays a little tune and that's it. The screen is black with nothing on it. At least, that's how it runs on Nestopia. I tried running the same cart in Mesen and I get a green screen and no audio! I don't understand why since it's the same game. I might have a malformed cartridge header.

Code: Select all

	org $BFF0

	db "NES",$1a		;ID
	db $01				;Rom pages (16k each)
	db $0				;CHR-ROM pages
	db %10000010		;mmmmFTBM		mmmm = mapper no bottom 4 bits , Four screen vram layout, Trainer at &7000, Battery ram at &6000, Mirror (0=horiz, 1=vert)
	db %00010000		;mmmm--PV 		mapper (top 4 bits...  Pc10 arcade, Vs unisystem )
	db 0				;Ram pages	(this might not be set up correctly)
	db 0,0,0,0,0,0,0	;			(this might not be set up correctly)
Could this be the cause? The only other game that uses the same mapper as mine is Japanese Castlevania 3, and I don't know how that game's header is set up. (I tried going to BFF0 in my game's ROM using Mesen's memory viewer and it didn't even match up with the above header either. I'm really confused right now)
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: My cart runs differently in different emulators

Post by lidnariq »

Why are you using mapper 24?

Note that you cannot rely on any power-up state, so your code must start in a fixed bank to initialize all state, if your mapper provides any. (If it does not, as on MMC1 or GNROM, you must provide enough code in every bank to initialize enough state to finish the rest of the initialization)
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: My cart runs differently in different emulators

Post by tokumaru »

puppydrum64 wrote: Sun May 02, 2021 7:11 pmMy test cartridge is pretty simple.
I'm guessing that by "cartridge" you mean a ROM file? I don't mean to be pedantic, but these are very different things that can be affected by different problems.
It plays a little tune and that's it. The screen is black with nothing on it.
Are you explicitly making the screen black by setting the first palette entry to $0F and moving the VRAM pointer away from $3F00-$3FFF, or are you just expecting the screen to be black because you did nothing to it? Never trust anything to be in a particular state on power up, if you want something to be a certain way, you must write the code to make it stay that way.
I don't understand why since it's the same game. I might have a malformed cartridge header.
If a program isn't written properly, you bet it will behave differently in different emulators and consoles! No emulator is perfect, and even different consoles have subtle differences between them, so you must make sure that your programs perform all tasks in a safe way. "Safe" usually means initializing everything (don't ever rely on any "default" states, there's usually no such thing), and being prepared for slight timing variations, interrupts, and anything that can disrupt the flow of the program.
I tried going to BFF0 in my game's ROM using Mesen's memory viewer and it didn't even match up with the above header either.
You're not supposed to see the iNES header in the memory viewer, since it's not part of the game itself and is never mapped into the 6502 addressing space. Its purpose is to provide the emulator with information on how to run the game. Some emulators are able to show the ROM file itself in the memory viewer/editor, but in this case the header would show up at $0000, not $BFF0, since it's at the very beginning of the file.

In order to know what went wrong, we'd have to take a look at the 6502 code.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: My cart runs differently in different emulators

Post by tepples »

lidnariq wrote: Sun May 02, 2021 7:23 pm Why are you using mapper 24?
A guess based on "plays a little tune" in OP: Mapper 24 and mapper 26 are the only iNES mappers that offer VRC6 audio.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

tokumaru wrote: Sun May 02, 2021 7:55 pmI'm guessing that by "cartridge" you mean a ROM file? I don't mean to be pedantic, but these are very different things that can be affected by different problems.
Yes, I meant ROM file.
Are you explicitly making the screen black by setting the first palette entry to $0F and moving the VRAM pointer away from $3F00-$3FFF, or are you just expecting the screen to be black because you did nothing to it? Never trust anything to be in a particular state on power up, if you want something to be a certain way, you must write the code to make it stay that way.
You're right, I assumed it would be black since I did nothing.

If a program isn't written properly, you bet it will behave differently in different emulators and consoles! No emulator is perfect, and even different consoles have subtle differences between them, so you must make sure that your programs perform all tasks in a safe way. "Safe" usually means initializing everything (don't ever rely on any "default" states, there's usually no such thing), and being prepared for slight timing variations, interrupts, and anything that can disrupt the flow of the program.
Oddly enough this is where I ran into even more strangeness. The header I'm using works perfectly fine, but if I try to use the same header as the Japanese version of Castlevania 3, NEStopia refuses to load the file and says "Corrupt file!"

I really don't understand why. The error message implies that there is something wrong with the header, not the game's code. But it should load like normal since it's the same header as a real game that works on NEStopia.



Here's the code. I cut out everything that isn't needed for the ROM to run on NEStopia properly. Anything I took out didn't change the fact that the game would not run on MESEN.

Code: Select all

	org $BFF0

	db "NES",$1a		;ID
	db $01				;Rom pages (16k each)
	db $0				;CHR-ROM pages
	db %10000010		;mmmmFTBM		mmmm = mapper no bottom 4 bits , Four screen vram layout, Trainer at &7000, Battery ram at &6000, Mirror (0=horiz, 1=vert)
	db %00010000		;mmmm--PV 		mapper (top 4 bits...  Pc10 arcade, Vs unisystem )
	db 0				;Ram pages	(this might not be set up correctly)
	db 0,0,0,0,0,0,0	;			(this might not be set up correctly)
	
nmihandler:	
	php		;This seems redundant but without these two lines Mesen will report a CPU crash.
	plp		;This seems redundant but without these two lines Mesen will report a CPU crash.			
	rti

irqhandler:
	rti					;Do nothing

RESET:	
	
	
	
	
init:

	lda #$00
	sta $9003 ;initializes VRC6 audio
	lda #$0f
	sta $9000
	lda #$56
	sta $9001
	lda #$83
	sta $9002


infloop:
	jmp infloop 	;prevents CPU jam while no code is present
	
	org $FFFA
	dw nmihandler			;FFFA - Interrupt handler
	dw RESET				;FFFC - Entry point
	dw irqhandler			;FFFE - IRQ Handler
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: My cart runs differently in different emulators

Post by lidnariq »

You missed what I said last time:
lidnariq wrote: Sun May 02, 2021 7:23 pm Note that you cannot rely on any power-up state, so your code must start in a fixed bank to initialize all state, if your mapper provides any. (If it does not, as on MMC1 or GNROM, you must provide enough code in every bank to initialize enough state to finish the rest of the initialization)
You *must* put your reset handler in $E000-$FFFF.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: My cart runs differently in different emulators

Post by Quietust »

puppydrum64 wrote: Mon May 03, 2021 10:06 am Oddly enough this is where I ran into even more strangeness. The header I'm using works perfectly fine, but if I try to use the same header as the Japanese version of Castlevania 3, NEStopia refuses to load the file and says "Corrupt file!"

I really don't understand why. The error message implies that there is something wrong with the header, not the game's code. But it should load like normal since it's the same header as a real game that works on NEStopia.
If you used the exact header, then I'd expect it to fail - after all, the header for 悪魔城伝説 (Akumajou Densetsu, the Japanese version of Castlevania 3) says there should be 256KB of PRG ROM and 128KB of CHR ROM, and unless your file was 393,232 bytes long (which I'm guessing it was not), a diagnosis of "corrupt file" would be totally correct.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

Quietust wrote: Mon May 03, 2021 11:07 am
puppydrum64 wrote: Mon May 03, 2021 10:06 am Oddly enough this is where I ran into even more strangeness. The header I'm using works perfectly fine, but if I try to use the same header as the Japanese version of Castlevania 3, NEStopia refuses to load the file and says "Corrupt file!"

I really don't understand why. The error message implies that there is something wrong with the header, not the game's code. But it should load like normal since it's the same header as a real game that works on NEStopia.
If you used the exact header, then I'd expect it to fail - after all, the header for 悪魔城伝説 (Akumajou Densetsu, the Japanese version of Castlevania 3) says there should be 256KB of PRG ROM and 128KB of CHR ROM, and unless your file was 393,232 bytes long (which I'm guessing it was not), a diagnosis of "corrupt file" would be totally correct.
I thought the header represented the maximum possible data, not what is actually contained. So for example I could fix it by padding the file with NOP commands?
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: My cart runs differently in different emulators

Post by Quietust »

puppydrum64 wrote: Mon May 03, 2021 1:05 pm I thought the header represented the maximum possible data, not what is actually contained. So for example I could fix it by padding the file with NOP commands?
The iNES header must specify the exact amount of data in the file - if it didn't, the emulator wouldn't be able to determine where the PRG ROM ended and where the CHR ROM started.

Padding is only relevant within a single bank, and your assembler should be able to handle that as long as you're using it properly (some assemblers watch "org" directives and do it for you, but others might need special "fill" commands).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

Quietust wrote: Mon May 03, 2021 1:12 pm
puppydrum64 wrote: Mon May 03, 2021 1:05 pm I thought the header represented the maximum possible data, not what is actually contained. So for example I could fix it by padding the file with NOP commands?
The iNES header must specify the exact amount of data in the file - if it didn't, the emulator wouldn't be able to determine where the PRG ROM ended and where the CHR ROM started.

Padding is only relevant within a single bank, and your assembler should be able to handle that as long as you're using it properly (some assemblers watch "org" directives and do it for you, but others might need special "fill" commands).
Hmm maybe I don't understand the concept. So let's say that I stick with the header that works (for now) and keep adding more code, will Nestopia eventually give me a corrupt file error at which point I will need to uodate the header to reflect the file size?
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

lidnariq wrote: Mon May 03, 2021 10:43 am You missed what I said last time:
lidnariq wrote: Sun May 02, 2021 7:23 pm Note that you cannot rely on any power-up state, so your code must start in a fixed bank to initialize all state, if your mapper provides any. (If it does not, as on MMC1 or GNROM, you must provide enough code in every bank to initialize enough state to finish the rest of the initialization)
You *must* put your reset handler in $E000-$FFFF.
How would I do this? I'm guessing it would be something like:

Code: Select all

.org $E000
RESET:

;your code goes here
But doesn't the program counter start at C000? If I put the reset code in $E000 it wouldn't automatically run when the game boots since there would be other code before it. Right?
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: My cart runs differently in different emulators

Post by lidnariq »

puppydrum64 wrote: Mon May 03, 2021 1:29 pm But doesn't the program counter start at C000? If I put the reset code in $E000 it wouldn't automatically run when the game boots since there would be other code before it. Right?
No. The program counter starts at the address that the NES's CPU loads from the cart.

In the same way that NMI jumps to the address at $FFFA, reset jumps to the address at $FFFC.

The VRC6 only guarantees that the last 8KB of the PRG ROM is accessible at addresses $E000-$FFFF, so your code must write to the VRC6 registers before you access anything at $8000-$DFFF.

(And your PRG ROM must be a power of 2 in size)
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: My cart runs differently in different emulators

Post by Quietust »

lidnariq wrote: Mon May 03, 2021 1:43 pm The VRC6 only guarantees that the last 8KB of the PRG ROM is accessible at addresses $E000-$FFFF, so your code must write to the VRC6 registers before you access anything at $8000-$DFFF.

(And your PRG ROM must be a power of 2 in size)
It's worth pointing out that, because the iNES file format requires PRG ROM sizes to be a multiple of 16,384 bytes, you'll need to ensure that your assembler emits at least 8,192 bytes of blank space between the iNES header and the beginning of your RESET code.

You haven't told us which assembler you're using, but it looks like you're using ASM6 so I think it'll be sufficient to put "ORG $C000" followed by "ORG $E000" immediately after your header (which I'm pretty sure should not have "ORG $BFF0" before it).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

Quietust wrote: Mon May 03, 2021 1:51 pm
lidnariq wrote: Mon May 03, 2021 1:43 pm The VRC6 only guarantees that the last 8KB of the PRG ROM is accessible at addresses $E000-$FFFF, so your code must write to the VRC6 registers before you access anything at $8000-$DFFF.

(And your PRG ROM must be a power of 2 in size)
It's worth pointing out that, because the iNES file format requires PRG ROM sizes to be a multiple of 16,384 bytes, you'll need to ensure that your assembler emits at least 8,192 bytes of blank space between the iNES header and the beginning of your RESET code.

You haven't told us which assembler you're using, but it looks like you're using ASM6 so I think it'll be sufficient to put "ORG $C000" followed by "ORG $E000" immediately after your header (which I'm pretty sure should not have "ORG $BFF0" before it).
I'm using VASM, I got it from chibiakumas.com
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

lidnariq wrote: Mon May 03, 2021 1:43 pm
puppydrum64 wrote: Mon May 03, 2021 1:29 pm But doesn't the program counter start at C000? If I put the reset code in $E000 it wouldn't automatically run when the game boots since there would be other code before it. Right?
No. The program counter starts at the address that the NES's CPU loads from the cart.

In the same way that NMI jumps to the address at $FFFA, reset jumps to the address at $FFFC.

The VRC6 only guarantees that the last 8KB of the PRG ROM is accessible at addresses $E000-$FFFF, so your code must write to the VRC6 registers before you access anything at $8000-$DFFF.

(And your PRG ROM must be a power of 2 in size)
Hmmm. I'm starting to think the VRC6 is a little too advanced for me at the moment. I really didn't understand what you were trying to tell me or how to do it.
Post Reply