There is no actual "ROM position $0000" -- this is purely a terminology thing, which is where the confusion is stemming from. I'm not even sure what you're trying to say here (it sure isn't "file offset $0000", so I think what you mean is PPU RAM $0000, but I'm not sure if you understand how that correlates with CHR-ROM or not).
So let's take some time to clarify about your setup and the memory mapping of
everything, because this will almost certainly help you understand:
Code:
.inesprg 1 ; 1 PRG bank
.ineschr 1 ; 1 CHR bank
.inesmap 0 ; No mapper
.inesmir 1 ; Vertical mirroring
...
.bank 0 ; PRG bank
.org $8000
...
.bank 1 ; CHR bank
.org $0000
.incbin "Spriteset.chr"
.incbin "Tileset.chr"
.bank 2 ; Vector bank
.org $FFFA
.dw NMI
.dw RESET
.dw 0
1. You're using mapper #0, a.k.a.
NROM, but more specifically NROM-128. NROM-128 consists of (1) 16KByte PRG bank, and (1) 8KByte CHR bank.
2. With NROM-128, CPU address space (a.k.a. "ROM", because it's read-only-memory) $8000-BFFF is mapped to the 1st 16KByte PRG bank/page in the ROM file. These would be the bytes at file offset $0010-400F.
3. With NROM-128, CPU address space (a.k.a. "ROM", because it's read-only-memory) $C000-FFFF is a mirror (think "copy") of the 1st 16KByte PRG bank/page in the ROM file. These would be the bytes at file offset $0010-400F.
4. The important thing to understand about items #2 and #3 above is that you're using 16KBytes of PRG, while the actual CPU memory map supports 32KBytes ($8000-FFFF). This is why your PRG bank gets "mirrored" (keep reading). Why that's important: because your RESET, NMI, and IRQ vectors need to reside within the very top of the PRG bank so that they get mapped to $FFFA-FFFF.
5. With NROM-128, PPU address space $0000-1FFF (a.k.a. CHR-ROM or VROM) is mapped to the 1st 8KByte CHR bank/page in the ROM file. These would be the bytes at file offset $4010 to end-of-file.
6. Your above code has actual problems, specifically you're stating ".inesprg 1" even though within your code you're trying to use two 16KB PRG banks (kind of. What was done there obviously isn't correct, indicating someone doesn't understand the memory map vs. how the assembler works). Furthermore, the
very last bank must be CHR. So all you're doing in your code is making a mess. I will show you how to fix this momentarily.
7. I strongly suggest, if using asm6, to use the
-l (dash lowercase ELL) flag to generate a listing file and actually take the time to read it. This can help you understand file offsets vs. what's getting generated + put where in the file -- because it matters.
Back to addressing. Here's a chart to help you, given how your code is right now (not the fixed version):
Code:
CPU address File offset Purpose
------------ ------------ --------------------------------------------------------------------
n/a $0000-000F iNES header (not used by the console, only emulators)
$0000-07FF n/a RAM (used for zero page, stack, etc.)
$2000-2007 n/a NES PPU registers
$4000-401F n/a NES APU and I/O registers
$6000-7FFF n/a SRAM (a.k.a. WRAM), but not used here
$8000-BFFF $0010-400F Code
$C000-FFFF $0010-400F Code (should include RESET/NMI/IRQ vectors)
PPU address File offset Purpose
------------ ------------ --------------------------------------------------------------------
$0000-0FFF $4010-500F Pattern table #0 (mapped to lower half of CHR-ROM bank #0)
$1000-1FFF $5010-<eof> Pattern table #1 (mapped to upper half of CHR-ROM bank #0)
$2000-23FF n/a Name table #0
$2400-27FF n/a Name table #1
$2800-2BFF n/a Name table #2
$2C00-2FFF n/a Name table #3
$3F00-3F1F n/a Palette
References:
And here is your fixed code:
Code:
.inesprg 1 ; 1 PRG bank
.ineschr 1 ; 1 CHR bank
.inesmap 0 ; No mapper
.inesmir 1 ; Vertical mirroring
...
.bank 0 ; PRG bank
.org $C000
...code here...
.org $FFFA
.dw NMI
.dw RESET
.dw IRQ
.bank 1 ; CHR bank
.incbin "Spriteset.chr"
.incbin "Tileset.chr"
Note that the base origin address is $C000, not $8000 here -- because essentially one 16KByte PRG bank means you should be treating your code as $C000-FFFF in CPU memory space, not $8000-BFFF.
Also since you're not using an IRQ handler per se, be sure to make a label called
IRQ and make its instruction
rti. You can even do something like this (there's nothing fancy about this):
Code:
NMI: ; NMI code
PHA ; Push A, X & Y to stack
TXA
...
TAX
PLA
IRQ:
RTI
Your code should then no longer "crash at $0000". The reason it was "crashing at $0000" was because your CHR-ROM banks were quite possibly being used as content within CPU memory space $C000-FFFF, and I'd bet money the last few bytes were all zeros, hence RESET vector was $0000, hence "crash at $0000". A code listing (see above) would shed light on this.
If you ever want to extend your code to use NROM-256 (that is: (2) 16KByte PRG banks, and (1) CHR bank), then it's quite simple:
Code:
.inesprg 2 ; 2 PRG banks
.ineschr 1 ; 1 CHR bank
.inesmap 0 ; No mapper
.inesmir 1 ; Vertical mirroring
...
.bank 0 ; PRG bank
.org $8000
...code here (up to 16KBytes)
.bank 1
.org $C000
...code here (up to 16KBytes minus vectors)...
.org $FFFA
.dw NMI
.dw RESET
.dw IRQ
.bank 2 ; CHR bank
.incbin "Spriteset.chr"
.incbin "Tileset.chr"
Alternately, you could try to fit all your code one single 32KByte bank (two 16KByte banks from the iNES header perspective):
Code:
.inesprg 2 ; 2 PRG banks
.ineschr 1 ; 1 CHR bank
.inesmap 0 ; No mapper
.inesmir 1 ; Vertical mirroring
...
.bank 0 ; PRG bank
.org $8000
...code here (up to 32KBytes minus vectors)...
.org $FFFA
.dw NMI
.dw RESET
.dw IRQ
.bank 1 ; CHR bank
.incbin "Spriteset.chr"
.incbin "Tileset.chr"
P.S. -- I have no idea what the
.bank pseudo-op does in whatever assembler you're using, so some of the advice I've given you may not be correct for your assembler. I have no idea what your assembler thinks the size of a "bank" is.