CPU memory map: Difference between revisions

From NESdev Wiki
Jump to navigationJump to search
(I'd recommend against adding mapper ports that overlap the APU test area)
mNo edit summary
 
(17 intermediate revisions by 8 users not shown)
Line 1: Line 1:
{| class="tabular"
{| class="tabular"
! First address || Size || Device
! Address range || Size || Device
|-
|-
| $0000 || $0800 || 2KB internal RAM
| $0000–$07FF || $0800 || 2 KB internal RAM
|-
|-
| $0800 || $0800 ||rowspan=3| [[Mirroring|Mirrors]] of $0000-$07FF
| $0800–$0FFF || $0800 ||rowspan=3| [[Mirroring#Memory Mirroring|Mirrors]] of $0000–$07FF
|-
|-
| $1000 || $0800
| $1000–$17FF || $0800
|-
|-
| $1800 || $0800
| $1800–$1FFF || $0800
|-
|-
| $2000 || $0008 || [[PPU_registers|NES PPU]] registers
| $2000–$2007 || $0008 || [[PPU registers|NES PPU registers]]
|-
|-
| $2008 || $1FF8 || Mirrors of $2000 every 8 bytes
| $2008–$3FFF || $1FF8 || Mirrors of $2000–$2007 (repeats every 8 bytes)
|-
|-
| $4000 || $0020 || [[APU|NES APU]] and [[2A03|I/O registers]]
| $4000–$4017 || $0018 || [[APU|NES APU]] and [[2A03|I/O registers]]
|-
|-
| $4020 || $BFE0 || Cartridge space: PRG ROM, PRG RAM, and [[mapper]] registers (See Note)
| $4018–$401F || $0008 || APU and I/O functionality that is normally disabled. See [[CPU Test Mode]].
|-
| $4020–$FFFF<br/>''• $6000–$7FFF<br/>• $8000–$FFFF'' || $BFE0<br/>''$2000<br/>$8000'' || Unmapped. Available for cartridge use.<br/>''Usually cartridge RAM, when present.<br/>Usually cartridge ROM and [[mapper]] registers.''
|}
|}


Note: Most common boards address ROM and Save/Work RAM in this format, especially in common iNES mappers:
* Some parts of the 2 KiB of internal RAM at $0000–$07FF have predefined purposes dictated by the 6502 architecture:
** $0000-$00FF: The zero page, which can be accessed with fewer bytes and cycles than other addresses
** $0100–$01FF: The page containing the stack, which can be located anywhere here, but typically starts at $01FF and grows downward
: Games may divide up the rest however the programmer deems useful. See [[Sample RAM map]] for an example allocation strategy for this RAM. Most commonly, $0200-$02FF is used for the OAM buffer to be copied to PPU OAM during vblank.


*$6000-$7FFF = Battery Backed Save or Work RAM
* The unmapped space at $4020-$FFFF can be used by cartridges for any purpose, such as ROM, RAM, and registers. Many common mappers place ROM and save/work RAM in these locations:
*$8000-$FFF9 = Usual ROM, commonly with Mapper Registers (see [[MMC1]] and [[UxROM]] for example)
** $6000–$7FFF: Battery-backed save or work RAM (usually referred to as WRAM or PRG-RAM)
** $8000–$FFFF: ROM and mapper registers (see [[MMC1]] and [[UxROM]] for examples)
: The cartridge is able to passively observe reads from and writes to any address in the CPU address space, even outside this unmapped space, except for reads from $4015, the only readable register that is internal to the CPU. The cartridge can map writable registers anywhere, but its readable memory can only be placed where it does not interfere with other readable hardware, which would produce a [[bus conflict]]. While cartridges can map readable memory at $4000-$4014 and $4018-$401F, a quirk in the 2A03's register decoding can cause DMA to misbehave if the CPU is halted while reading from $4000-$401F, so it is recommended that cartridges only map readable memory from $4020-$FFFF.


The CPU expects three addresses called "vectors" in fixed places at the end of the cartridge space, like so:
* If using [[APU DMC|DPCM playback]], samples are limited to the following practical range:
** $C000–$FFF1: DPCM sample data
: Sample playback wraps around from $FFFF to $8000. The highest sample starting address is $FFC0 and longest sample is $FF1 bytes, so the full DPCM range is $C000-$FFFF and $8000-$8FB0, but making use of the wraparound is challenging because of banking and the presence of the CPU vectors.


*$FFFA-$FFFB = NMI vector
* The CPU expects interrupt vectors in a fixed place at the end of the unmapped space:
*$FFFC-$FFFD = Reset vector
** $FFFA–$FFFB: NMI vector, which points at an [[NMI]] handler
*$FFFE-$FFFF = IRQ/BRK vector
** $FFFC–$FFFD: Reset vector, which points at [[init code|code to initialize the NES chipset]]
** $FFFE–$FFFF: IRQ/BRK vector, which may point at a mapper's [[IRQ|interrupt]] handler (or, less often, a handler for APU interrupts)
: These vectors are supplied by the cartridge. Unless a mapper fixes $FFFA–$FFFF to some known bank (normally by fixing an entire bank-sized region at the top of the address space, such as $C000-$FFFF, to a specific bank) or uses some sort of reset detection, the vectors (and a suitable reset code stub) must be present in all banks.


Any mapper that switches $E000-$FFF9 will switch $FFFA-$FFFF along with it.
* Reading from memory that is not mapped to anything normally returns [[Open bus behavior|open bus]]. The cartridge hardware may affect open bus behavior across the entire CPU address space, such as by pulling bits high or low.
If a mapper doesn't fix $C000-$FFFF to the last bank or use some sort of reset detection, the vectors need to be stored in all banks.

Latest revision as of 15:05, 19 March 2024

Address range Size Device
$0000–$07FF $0800 2 KB internal RAM
$0800–$0FFF $0800 Mirrors of $0000–$07FF
$1000–$17FF $0800
$1800–$1FFF $0800
$2000–$2007 $0008 NES PPU registers
$2008–$3FFF $1FF8 Mirrors of $2000–$2007 (repeats every 8 bytes)
$4000–$4017 $0018 NES APU and I/O registers
$4018–$401F $0008 APU and I/O functionality that is normally disabled. See CPU Test Mode.
$4020–$FFFF
• $6000–$7FFF
• $8000–$FFFF
$BFE0
$2000
$8000
Unmapped. Available for cartridge use.
Usually cartridge RAM, when present.
Usually cartridge ROM and mapper registers.
  • Some parts of the 2 KiB of internal RAM at $0000–$07FF have predefined purposes dictated by the 6502 architecture:
    • $0000-$00FF: The zero page, which can be accessed with fewer bytes and cycles than other addresses
    • $0100–$01FF: The page containing the stack, which can be located anywhere here, but typically starts at $01FF and grows downward
Games may divide up the rest however the programmer deems useful. See Sample RAM map for an example allocation strategy for this RAM. Most commonly, $0200-$02FF is used for the OAM buffer to be copied to PPU OAM during vblank.
  • The unmapped space at $4020-$FFFF can be used by cartridges for any purpose, such as ROM, RAM, and registers. Many common mappers place ROM and save/work RAM in these locations:
    • $6000–$7FFF: Battery-backed save or work RAM (usually referred to as WRAM or PRG-RAM)
    • $8000–$FFFF: ROM and mapper registers (see MMC1 and UxROM for examples)
The cartridge is able to passively observe reads from and writes to any address in the CPU address space, even outside this unmapped space, except for reads from $4015, the only readable register that is internal to the CPU. The cartridge can map writable registers anywhere, but its readable memory can only be placed where it does not interfere with other readable hardware, which would produce a bus conflict. While cartridges can map readable memory at $4000-$4014 and $4018-$401F, a quirk in the 2A03's register decoding can cause DMA to misbehave if the CPU is halted while reading from $4000-$401F, so it is recommended that cartridges only map readable memory from $4020-$FFFF.
  • If using DPCM playback, samples are limited to the following practical range:
    • $C000–$FFF1: DPCM sample data
Sample playback wraps around from $FFFF to $8000. The highest sample starting address is $FFC0 and longest sample is $FF1 bytes, so the full DPCM range is $C000-$FFFF and $8000-$8FB0, but making use of the wraparound is challenging because of banking and the presence of the CPU vectors.
  • The CPU expects interrupt vectors in a fixed place at the end of the unmapped space:
    • $FFFA–$FFFB: NMI vector, which points at an NMI handler
    • $FFFC–$FFFD: Reset vector, which points at code to initialize the NES chipset
    • $FFFE–$FFFF: IRQ/BRK vector, which may point at a mapper's interrupt handler (or, less often, a handler for APU interrupts)
These vectors are supplied by the cartridge. Unless a mapper fixes $FFFA–$FFFF to some known bank (normally by fixing an entire bank-sized region at the top of the address space, such as $C000-$FFFF, to a specific bank) or uses some sort of reset detection, the vectors (and a suitable reset code stub) must be present in all banks.
  • Reading from memory that is not mapped to anything normally returns open bus. The cartridge hardware may affect open bus behavior across the entire CPU address space, such as by pulling bits high or low.