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.
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.