Topics

UTTORI ASM ยท IN DEVELOPMENT

SNES memory maps

Convert SNES CPU addresses to ROM offsets for supported cartridge mappers.

On this page

A SNES CPU address is not a file offset. The cartridge decoder maps portions of the 24-bit bus to ROM, often with mirrors. Read the wiki's memory mapping overview for the hardware picture. Read src/target/address-space.ts for the exact formulas used here.

Try an address conversion

Enter a mapper and a 24-bit CPU address. The conversion uses the same address-space implementation as the SNES assembler; an address in RAM or an unmapped hole returns an explicit unmapped result.

Address conversionROM offset: $000000 Preferred CPU address: $808000

Expected output

Mapper directives

Directive Internal Mode ROM Capacity Represented Preferred CPU Window Header File Offset
lorom lorom Up to 4 MiB Banks with $8000-$FFFF ROM windows $7FC0
hirom hirom Up to 4 MiB Full high-bank windows $FFC0
exlorom exlorom Up to 8 MiB Extended LoROM windows $FFC0 in current checksum policy
exhirom exhirom Up to 8 MiB Extended HiROM windows $FFC0
sfxrom sfxrom Super FX layout GSU-compatible ROM windows $FFC0
sa1rom sa1rom Bank-selectable SA-1 layout LoROM-like and C-F windows $7FC0
fullsa1rom bigsa1rom Full 8 MiB SA-1 layout Mirrored half-bank plus C-F windows $7FC0
norom norom 16 MiB flat logical space Address equals output offset none

The default is lorom. Mapper switches are allowed during a source file and are exercised by mappers.asm, although real projects are usually easier to reason about with one map per output.

fastrom is currently an accepted no-op. It does not alter mapping, the internal header byte, or any generated timing property. FastROM is a cartridge and CPU timing concern, see the wiki's FastROM tutorial, set the ROM header and runtime registers as your program requires.

sa1rom optionally accepts four decimal bank selectors:

sa1rom 0,1,2,3

They configure the four one-megabyte Super MMC regions used by the mapper. Without arguments the same 0,1,2,3 arrangement is installed. The SA-1 overview and SA-1 registers explain the coprocessor hardware. This directive only controls assembler-side ROM translation.

org, base, and Address Stacks

org address moves the physical/logical write position:

lorom
org $018000
BankOne:
  nop

The address must be within the target's 24-bit range. Writing to an unmapped SNES address advances layout but produces no ROM byte. Use snestopc() or the map source when in doubt.

base address changes the logical address seen by labels and operands without seeking the physical output cursor. base off returns to the saved physical/base relationship:

org $128000
base $7E2000
BufferView:
  db $00
base off

pushpc / pullpc save and restore the full output cursor state. pushbase / pullbase save and restore the current logical base address. Pulling an empty stack is an error.

Bank Crossing

The default is check bankcross full, also spelled on. Multi-byte writes may not cross a 64 KiB bank boundary. Modes are:

Command Boundary Enforced
check bankcross off No boundary check. Mapper-specific PC wrapping is enabled
check bankcross half 32 KiB half-bank boundary
check bankcross full 64 KiB bank boundary
check bankcross on Alias of full

This validation runs before multi-byte output. The exact edge cases are captured in bankcross.asm and half_bank_check.asm.

Address Conversion Functions

dl snestopc($808000) ; logical SNES address -> file offset
dl pctosnes($000000) ; file offset -> preferred logical mirror

An unmapped conversion returns -1. The preferred address produced by pctosnes() is canonical for this implementation, not a promise that no mirrored CPU address reaches the same ROM byte.