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.Quietust wrote: ↑Mon May 03, 2021 1:51 pmIt'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).
My cart runs differently in different emulators
Moderator: Moderators
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: My cart runs differently in different emulators
Re: My cart runs differently in different emulators
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.
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.
Re: My cart runs differently in different emulators
All this is true!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.
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.
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: My cart runs differently in different emulators
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 banklidnariq wrote: ↑Tue May 04, 2021 3:16 pmAll this is true!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.
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.
Re: My cart runs differently in different emulators
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
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
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: My cart runs differently in different emulators
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 bankslidnariq 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
Re: My cart runs differently in different emulators
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.puppydrum64 wrote: ↑Tue May 04, 2021 5:39 pm What I don't quite get is how the NES knows which bank is active
The extra hardware on the cartridge is what keeps track of what bank(s) is(are) active.
That's a function of the specific assembler you're using.or how to place different sections of code into different banks
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.
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: My cart runs differently in different emulators
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.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.
- Controllerhead
- Posts: 314
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: My cart runs differently in different emulators
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
Re: My cart runs differently in different emulators
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.
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.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: My cart runs differently in different emulators
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.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.
They’re definitely going to be different numbers with your mapper, but hope that helps.
-
- Posts: 160
- Joined: Sat Apr 24, 2021 7:25 am
Re: My cart runs differently in different emulators
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
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: My cart runs differently in different emulators
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?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
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.
- Controllerhead
- Posts: 314
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: My cart runs differently in different emulators
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.
Also, if you were trying to bankswitch the first 16KB of VRC6, that size would be $4000, not $2000.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: My cart runs differently in different emulators
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.
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.