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

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).
To be honest I never really looked into how headers worked. I knew that the program counter on the test ROMs I was using always started at $C000. I made the assumption that .org $BFF0 told the assembler to put the next data block at that address, which would cause the header to be stored in addresses $BFF0 to $BFFF, after which would come $C000 where the code begins. I was under the impression that $BFF0 was used so that the header wouldn't be seen by the program counter and thus run as executable code causing a crash.
Pokun
Posts: 2675
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: My cart runs differently in different emulators

Post by Pokun »

A 6502 CPU always starts with the address it finds at the RESET vector ($FFFC) in the PC at boot/reset. The vectors is the part that Chibiakumas calls "Cartridge Footer".

Chibiakumas seems to use an "org $BFF0" before his header. It might be needed to be done in VASM to get the file size right, otherwise you can probably remove it if you want (but you still need the "org $C000" and "org $E000" or whatever your mapper uses) as the header isn't really part of the ROM nor the address space. It's just a bunch of metadata tucked into the file before the ROM starts. If you make your own cartridge and burn an EPROM, you need to remove the header first, as it's only used by emulators and flashcarts telling them the size of the ROM and how the cartridge is wired.
lidnariq
Posts: 11429
Joined: Sun Apr 13, 2008 11:12 am

Re: My cart runs differently in different emulators

Post by lidnariq »

puppydrum64 wrote: Tue May 04, 2021 2:28 pm I made the assumption that .org $BFF0 told the assembler to put the next data block at that address, which would cause the header to be stored in addresses $BFF0 to $BFFF, after which would come $C000 where the code begins.
All this is true!

But it's also an abstraction of what the NES itself physically does.

When the 6502 CPU inside the NES first turns on, it does the following things:
* Read three bytes from the stack (for historical reasons, but for no purpose)
* Read a byte from $FFFC
* Read a byte from $FFFD
* Start executing code at the address specified in the above two bytes.

And that's all you have to care about for games that run on PCBs that can only have 32KB of code. (Mapper 0, 3, some others)

The problem you're running into is that some PCBs ("mappers") can address more than 32KB of code.

The way they do this is by making certain "physical" addresses - what the CPU thinks it's reading from - correspond to a changeable different portion of ROM. So if one uses one of these mappers, your code must handle that, and initialize that, accordingly.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

lidnariq wrote: Tue May 04, 2021 3:16 pm
puppydrum64 wrote: Tue May 04, 2021 2:28 pm I made the assumption that .org $BFF0 told the assembler to put the next data block at that address, which would cause the header to be stored in addresses $BFF0 to $BFFF, after which would come $C000 where the code begins.
All this is true!

But it's also an abstraction of what the NES itself physically does.

When the 6502 CPU inside the NES first turns on, it does the following things:
* Read three bytes from the stack (for historical reasons, but for no purpose)
* Read a byte from $FFFC
* Read a byte from $FFFD
* Start executing code at the address specified in the above two bytes.

And that's all you have to care about for games that run on PCBs that can only have 32KB of code. (Mapper 0, 3, some others)

The problem you're running into is that some PCBs ("mappers") can address more than 32KB of code.

The way they do this is by making certain "physical" addresses - what the CPU thinks it's reading from - correspond to a changeable different portion of ROM. So if one uses one of these mappers, your code must handle that, and initialize that, accordingly.
So you mean like bank switching? I never really understood how that works, other than you cannot JMP or JSR to code in an unloaded bank
lidnariq
Posts: 11429
Joined: Sun Apr 13, 2008 11:12 am

Re: My cart runs differently in different emulators

Post by lidnariq »

Think of bank switching as like an elevator in a hotel. At first, everything looks the same on each floor¹, but if you check in the rooms you discover that there are different guests on each floor.

Taking the elevator is like switching banks. If you don't know what floor you're on, you have to first ride the elevator to the right floor before you can find the guest you want to talk to.



¹ for the purpose of this metaphor I'm pretending that each floor is decorated the same
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

lidnariq wrote: Tue May 04, 2021 5:00 pm Think of bank switching as like an elevator in a hotel. At first, everything looks the same on each floor¹, but if you check in the rooms you discover that there are different guests on each floor.

Taking the elevator is like switching banks. If you don't know what floor you're on, you have to first ride the elevator to the right floor before you can find the guest you want to talk to.



¹ for the purpose of this metaphor I'm pretending that each floor is decorated the same
So the memory addresses are still numbered the same they just have different instructions stored in them. I'm familiar with that concept- I first got started with NESMaker (which uses mapper 30 and has a fixed bank $1F and switchable banks $00 to $1E). What I don't quite get is how the NES knows which bank is active or how to place different sections of code into different banks
lidnariq
Posts: 11429
Joined: Sun Apr 13, 2008 11:12 am

Re: My cart runs differently in different emulators

Post by lidnariq »

puppydrum64 wrote: Tue May 04, 2021 5:39 pm What I don't quite get is how the NES knows which bank is active
It doesn't. All the NES knows is how to ask who's in room #$F000, not what floor it's on ... or even that there's a concept of multiple floors.

The extra hardware on the cartridge is what keeps track of what bank(s) is(are) active.
or how to place different sections of code into different banks
That's a function of the specific assembler you're using.

The simplest thing that could possibly work is to start with ".org 0xc000" and then add 8192 bytes (".skip 0x2000") so that your code is in the VRC6's fixed bank.

And mark your header as only having one 16KiB PRG bank.
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

Pokun wrote: Tue May 04, 2021 2:59 pm A 6502 CPU always starts with the address it finds at the RESET vector ($FFFC) in the PC at boot/reset. The vectors is the part that Chibiakumas calls "Cartridge Footer".

Chibiakumas seems to use an "org $BFF0" before his header. It might be needed to be done in VASM to get the file size right, otherwise you can probably remove it if you want (but you still need the "org $C000" and "org $E000" or whatever your mapper uses) as the header isn't really part of the ROM nor the address space. It's just a bunch of metadata tucked into the file before the ROM starts. If you make your own cartridge and burn an EPROM, you need to remove the header first, as it's only used by emulators and flashcarts telling them the size of the ROM and how the cartridge is wired.
I still don't understand what "org $E000" is for, is that a VRC6 thing specifically? I've noticed that putting org $E000 after org $C000 causes one of Chibiakumas's test roms to do nothing rather than draw a character to the screen like it was supposed to.
User avatar
Controllerhead
Posts: 314
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: My cart runs differently in different emulators

Post by Controllerhead »

puppydrum64 wrote: Tue May 04, 2021 6:08 pm I still don't understand what "org $E000" is for
ORG is a way to tell the assembler where your code and data is. The assembler needs to know this to reference your labels properly. In a 32KB NROM, it's very straight forward: your usable address space is between $8000-$FFFF, pop in an ORG $XXXX, and your proceeding code and data will be placed right after that ORG. Done.

When dealing with bankswitching, it's a bit more complicated. You have to align your ORG's to where your data is going to be. VRC6 has a 16KB switchable bank at $8000-$BFFF, so, say you wanted to have a 64KB of PRG with VRC6 switched in that region. You would need 3 ORGs that started at $8000, each containing up to 16KB of your code and data, or up to $BFFF. Whichever bank you have open out of those 3 ORG's is what data and code you can currently use: it will appear in $8000-$BFFF. It's up to you to keep track of your program and know what bank you have currently open, and what parts of your code and data you can currently use.

So how does the program initially boot with all of this switching around? Well, the most common solution is to have a fixed bank at the end of the ROM. The 6502 has special addresses at $FFFA-$FFFF that it uses to boot and handle interrupts, so this solution makes the most sense. With VRC6 (and several others), the last 8KB of your code cannot be switched out, and that will start at $E000. To put code there, use ORG $E000 near the end of your program: That's what it means and what it is used for. This is where you want your boot routines and other parts of your program that you want accessible at all times.

Anyway, I hope this makes sense!

EDIT: In ASM6, you use BASE instead of ORG to retro-set addresses for multiple banks. VASM seems to use ORG according to the docs, but, i'm honestly not sure... ugh
Image
Pokun
Posts: 2675
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: My cart runs differently in different emulators

Post by Pokun »

I didn't mean that ORG was a mapper-specific directive (VASM is just a 6502 assembler with no NES-specific functionality), I just meant where in the address space the mapper you use puts its ROM in. Anything between $4020-$FFFF* in the address space can technically be used by the cartridge to map stuff to (and by stuff I mean ROM, RAM and mapper hardware I/O) as everything before that is used by hardware inside the NES, like the 2 kB RAM ($0000-$07FF), PPU I/O ($2000-$2007), and APU, DMA and controller I/O ($4000-$4017). $4018-$401F is used for some test stuff which isn't available on all Famicom/NES models.

The cartridge can also map a larger ROM to the same small space by temporarily changing what part of the ROM chip is mapped to that ROM space it uses (the elevator metaphor). The hardware that maps the ROM must be included on the cartridge, and this hardware is what we call a "mapper".

The simplest cartridge type used by licensed games is the NROM board. It doesn't really have a mapper, it just connects its two ROM chips directly to the address and data lines available in the cartridge slot, which limits its PRG-ROM size to 32 kB (at $8000-$FFFF) and CHR-ROM to 8 kB (mapped to the PPU address space) due to how it's wired.


*Actually I heard the stuff in $4018-$401F can also be used by the cartridge because it's open bus, but that's details.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: My cart runs differently in different emulators

Post by unregistered »

Controllerhead wrote: Tue May 04, 2021 8:05 pm It's up to you to keep track of your program and know what bank you have currently open, and what parts of your code and data you can currently use.
Mesen also displays what banks are currently being used at the bottom of the debug window. I’m using mapper MMC1 and now the debugger’s left green box says 8000 and has an $01 in the center; the right green box says C000 and has an $0F in the center; so my first bank being used is bank1 and my second is bank15.

They’re definitely going to be different numbers with your mapper, but hope that helps. 🙂
puppydrum64
Posts: 160
Joined: Sat Apr 24, 2021 7:25 am

Re: My cart runs differently in different emulators

Post by puppydrum64 »

I think I'm starting to get it but let's see if I've got this right.

Code: Select all


;Header
	db "NES",$1a		;ID
	db $02				;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	
	db 0,0,0,0,0,0,0	;
	
	
	org $8000
	skip $2000
	;bank 1
	
	org $8000
	skip $2000
	;bank 2
	
	org $8000
	skip $2000
	;bank 3
	
	
	
	org $C000
	
	org $E000
	
	nmihandler:
	
	rti
	
	irqhandler:
	
	rti
	
	RESET:
	
	;YOUR CODE GOES HERE
	
	org $FFFA
	dw nmihandler
	dw RESET
	dw irqhandler
	
	
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: My cart runs differently in different emulators

Post by unregistered »

puppydrum64 wrote: Wed May 05, 2021 3:42 pm I think I'm starting to get it but let's see if I've got this right.

Code: Select all


;Header
	db "NES",$1a		;ID
	db $02				;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	
	db 0,0,0,0,0,0,0	;
	
	
	org $8000
	skip $2000
	;bank 1
	
	org $8000
	skip $2000
	;bank 2
	
	org $8000
	skip $2000
	;bank 3
	
	
	
	org $C000
	
	org $E000
	
	nmihandler:
	
	rti
	
	irqhandler:
	
	rti
	
	RESET:
	
	;YOUR CODE GOES HERE
	
	org $FFFA
	dw nmihandler
	dw RESET
	dw irqhandler
	
	
hmmm… I’ve never used the VRC6 mapper, but I’m noticing that you’ve set your CHR-ROM pages to 0. So either you are somehow using CHR-RAM, or your game is not meant to display any type of CHR graphic on the screen?

For my MMC1 with CHR-ROM, I was told to include the CHR files at $10000 (at the very end of the code you’ve provided). But, now with my version-of-MMC1 header set for using CHR-RAM, those CHR-ROM files starting at $10000 are invalid for me.
User avatar
Controllerhead
Posts: 314
Joined: Tue Nov 13, 2018 4:58 am
Location: $4016
Contact:

Re: My cart runs differently in different emulators

Post by Controllerhead »

The bank space you reserved doesn't seem to line up with the 32KB of PRG in your header, either.
Also, if you were trying to bankswitch the first 16KB of VRC6, that size would be $4000, not $2000.
Image
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: My cart runs differently in different emulators

Post by unregistered »

According to the wiki:

https://wiki.nesdev.com/w/index.php/VRC6

VRC6 has 8 1kb switchable CHR-ROM banks… so, starting at $10000, include your 1kb files.

That page also states that VRC6 has a maximum 256kb CHR-ROM space. I’m sure it also explains how to bank switch the VRC6 CHR banks.

(1kb is kind of small; 1kb == $0400; your first 1kb CHR-ROM file would fill up $10000 - $103FF; or, you could include a 4kb CHR-ROM file between $10000 - $10FFF and just arrange your 4kb file while remembering that it will be separated into 4 banks.)

(There are even mappers that use 8kb CHR banks; I just talked about using 4kb files bc my MMC1 was set to use 4kb CHR banks.)


And, one last kind note from me: Since it’s on a computer, your first bank, of PRG-ROM PRG-RAM CHR-ROM or CHR-RAM, is bank0. :)
Post Reply