LoRom Model


  1. Summary
  2. Conventions / Key Definitions
  3. Introduction
  4. LoRom Cartridges
  5. Connections
  6. Memory Map
  7. Notes

1. Summary

LoRom is a memory map produced from connecting ROM address lines to CPU lines as detailed in Section 5. It causes ROM chunks in SNES to be max 32KB wide ($8000 bytes), and are typically fetched from the $8000-FFFF region. Regular LoRom cartridges map up to 32Mbit ROM.

I want to take a moment to explain what I mean by regular. For developers, you may want to design a cartridge that does cool new things. Let me tell you LoRom is not limited to 32Mb, or even does that 32Mb need to be used by ROM. You can map anything to these locations. Say you are in my shoes, I am designing a cartridge for SNES Tracker program, that uses MUCH more SRAM than the typical SNES game. So, people who just want to play SNES games on real hardware by hacking a cartridge, those are the guys that want to make sure they reproduce the typical memory map. However, this document exists to unlock the true power behind memory mapping and show you that there really are no rules once you learn the power to mapping it yourself. Still, I do stick to a typical LoRom convention in this article, so that it is easy for people to digest. However, when I first learned about SNEs and read about mirrors in the memorymap, all that shit was new to me so I thought it was 'like, a SNES thing.' Nope. Memory mapping is actually a concept you can learn that is outside the scope of SNES. It comes with time. I've been doing this stuff for years now. Many years.

This document explains and illustrates the map. If you have no idea what you are doing, I suggest you go to the Intro.

This docu also outlines in full every ROM chunk to its SNES location along with details on electrical connections of on-cart peripherals (ROM+SRAM). I am confident nothing is amiss, however I am not yet verified. If you can help in verifying this document, Email me.

2. Conventions / Key Definitions

I list some notes on my writing style here, as well as key definitions.

3. Introduction

What is a Memory Map

The memory map shows the addresses where each type of memory is located. for SNES, the address range is 24 bits wide (3 bytes). In hex, this is from $00:0000 - $FF:FFFF

Let's see the inside of a cartridge:

This is a Super Mario World cart. We are looking at a few different things here. Let's point it out:

What is LoRom

LoRom's map comes from the way electrical address connections are made between the SNES Address Bus A and the ROM. LoRom is the map that results from this connection. In LoRom, 32KB MAX of ROM gets mapped in any given 64KB SNES bank. Some SNES banks map only 32K from the cart, others map all 64K. The banks that map all 64K with ROM connected in this manner will map mirrored 32K mirror chunks. 0000-7FFF will match 8000-FFFF.

Note: According to one of Neviksti's documents, the MAD-1 does not map the low 32K of the 64K cart chunks. The low 32K is unmapped (Open Bus).

LoRom's key trait is that the ROM chip doesn't connect its A15 to SNES A15. Instead, it connects its A15 to SNES A16, and A16+ to SNES A17+. That's a shift, and it causes 64KB ($10000 bytes) chunks of SNES space to only be mapped with no greater than 32KB ($8000) of cart data. There's a point to this. The benefit here is that ROM gets mapped automagically into the System Banks 00-3F:$8000-FFFF. The desire to do this comes from SNES banks 00-3f being system banks with access to other system hardware from thereign; for easy interfacing with hardware registers and RAM. Space-wise, the only downside is that when you get to Banks $40+ (64K), you can only map 32K. The 32K gets mapped twice for the whole 64K, because of the A15 ordeal. So, having said all that. I will keep the model given in this document in the most common form I can consider for LoRom, with the banks 80-FF a mirror of 00-7f. You could create a lorom cart that puts different data into those upper banks. You can map up to 63Mbits (not a typo) this way in the lorom model.

4. Reference LoRom Cartridges

TitleROM Size (Mb)SRAM Size (Kb)
Super Mario World 4 16
Mario Paint 8 256
Tecmo Superbowl III - Final Edition 16 256
NBA Jam TE 24 16
Tokimeki Memorial 32 64
For More, see Jensma

5. Address Line Connections

   X = No Connection
   Connections are horizontal

A23 X X
A22 A21 X
A21 A20 X
A20 A19 X
A19 A18 X
A18 A17 X
A17 A16 X
A16 A15 X
A15 X X
A14 A14 A14
A13 A13 A13
A12 A12 A12
A11 A11 A11
A10 A10 A10
A9 A9 A9
A8 A8 A8
A7 A7 A7
A6 A6 A6
A5 A5 A5
A4 A4 A4
A3 A3 A3
A2 A2 A2
A1 A1 A1
A0 A0 A0

Understanding Why LoRom Maps ROM Twice

Ok read this if you don't understand clearly why the ROM is getting mapped twice.

You already know, by me telling you, that 0000-7FFF and 8000-FFFF get mapped with the same data. Even if you don't understand it, remember SNES A15 is NC to ROM, even if you don't understand it, just don't forget that. We are going to look at the transition between the two 32K chunks of a ROM SNES Bank:

Table 1 - $7FFF
Binary 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Address Bit# 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Table 1 shows the binary value for $7FFF. Address Bit marks the number of the bit. In this example, the address bits count from 0-16, that's 17 bits.

Address bits are prefixed with 'A'

7FFF - it forms an address such that A0-A14 are all 1. Please pump some binary values representing 0000-7fff into a calculator, you'll see that A15 is never set.

Now, we're going to add 1 to 7FFF. $7FFF+1 = $8000. Let's translate to binary:

$8000 A16 A15 A14 A13 A12 A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
Binary 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Ah see what happened, A15 is now '1'. The other bits have reset to 0. LoRom does not connect its ROM to A15. You can think of it as - it's pretending A15 is always 0. when you pretend A15 of $8000 is 0, you wind up with the number 0. SNES still knows it is counting with A15 set.

Thus, the ROM is being repeated again from 0000-7FFF, to $8000-FFFF, the SNES is still keeping track of its address (8000-FFFF). Now, you should basically understand why the ROM repeats in any given bank. To Fully understand it, know this: different banks map different ROM data. We can observe how that works next. When the SNES is at address $FFFF, it will increment to $01:0000. Let's look at that. So let's see what happens when SNES $FFFF gets incremented. First, let's look at $FFFF in binary.

$FFFF A16 A15 A14 A13 A12 A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
Binary 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Then we increment it to $010000

$01:0000 A16 A15 A14 A13 A12 A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
Binary 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

here, A16 becomes set, and since SNES A16 is connected to the ROM's A15, the ROM will now output from $00:8000. This introduces a number of new concepts. The ROM has its own address space from the SNES memory map. You can start to understand this just by reading this document, since I map all the ROM sections to their corresponding SNES mapped sections. . See the Address Connection between SNES and ROM to see how all the lines are connected to each other.

The basic gist of it is that different SNES banks map different ROM data. That data will be visible in every bank at $8000, aside from System RAM 7e-7f. On top of this, ROM data within a bank may also be mapped in 0000-7fff, only for banks (40-6F - the 64K Cart banks). I call them them cart banks. You may call them ROM banks. Cart banks is better because ultimately ROM does not have to be mapped there, any on-cart peripherial can be mapped

6. Memory Map

  1. $00-3F : System Area
  2. $40-6F : All ROM
  3. $70-7D : SRAM + ROM
  4. $7E-7F : System RAM
  5. $80-FF : Upper Mirror

Banks $00-3f : System Area

SNES Address Description
$0000-$1FFF System RAM
$2000-$20FF Unimplemented
$2100-$21FF PPU
$2200-$3FFF Unimplemented
$4000-$43FF Internal CPU Registers
$4400-$5FFF Unimplemented
$6000-$7FFF Unimplemented
ROM Address SNES Address
$00:0000-7fff $00:8000-FFFF
$00:8000-ffff $01:8000-FFFF
$01:0000-7fff $02:8000-FFFF
$01:8000-ffff $03:8000-FFFF
$02:0000-7fff $04:8000-FFFF
$02:8000-ffff $05:8000-FFFF
$03:0000-7fff $06:8000-FFFF
$03:8000-ffff $07:8000-FFFF
$04:0000-7fff $08:8000-FFFF
$04:8000-ffff $09:8000-FFFF
$05:0000-7fff $0a:8000-FFFF
$05:8000-ffff $0b:8000-FFFF
$06:0000-7fff $0c:8000-FFFF
$06:8000-ffff $0d:8000-FFFF
$07:0000-7fff $0e:8000-FFFF
$07:8000-ffff $0f:8000-FFFF
ROM Address SNES Address
$08:0000-7fff $10:8000-FFFF
$08:8000-ffff $11:8000-FFFF
$09:0000-7fff $12:8000-FFFF
$09:8000-ffff $13:8000-FFFF
$0a:0000-7fff $14:8000-FFFF
$0a:8000-ffff $15:8000-FFFF
$0b:0000-7fff $16:8000-FFFF
$0b:8000-ffff $17:8000-FFFF
$0c:0000-7fff $18:8000-FFFF
$0c:8000-ffff $19:8000-FFFF
$0d:0000-7fff $1a:8000-FFFF
$0d:8000-ffff $1b:8000-FFFF
$0e:0000-7fff $1c:8000-FFFF
$0e:8000-ffff $1d:8000-FFFF
$0f:0000-7fff $1e:8000-FFFF
$0f:8000-ffff $1f:8000-FFFF
ROM Address SNES Address
$10:0000-7fff $20:8000-FFFF
$10:8000-ffff $21:8000-FFFF
$11:0000-7fff $22:8000-FFFF
$11:8000-ffff $23:8000-FFFF
$12:0000-7fff $24:8000-FFFF
$12:8000-ffff $25:8000-FFFF
$13:0000-7fff $26:8000-FFFF
$13:8000-ffff $27:8000-FFFF
$14:0000-7fff $28:8000-FFFF
$14:8000-ffff $29:8000-FFFF
$15:0000-7fff $2a:8000-FFFF
$15:8000-ffff $2b:8000-FFFF
$16:0000-7fff $2c:8000-FFFF
$16:8000-ffff $2d:8000-FFFF
$17:0000-7fff $2e:8000-FFFF
$17:8000-ffff $2f:8000-FFFF
ROM Address SNES Address
$18:0000-7fff $30:8000-FFFF
$18:8000-ffff $31:8000-FFFF
$19:0000-7fff $32:8000-FFFF
$19:8000-ffff $33:8000-FFFF
$1a:0000-7fff $34:8000-FFFF
$1a:8000-ffff $35:8000-FFFF
$1b:0000-7fff $36:8000-FFFF
$1b:8000-ffff $37:8000-FFFF
$1c:0000-7fff $38:8000-FFFF
$1c:8000-ffff $39:8000-FFFF
$1d:0000-7fff $3a:8000-FFFF
$1d:8000-ffff $3b:8000-FFFF
$1e:0000-7fff $3c:8000-FFFF
$1e:8000-ffff $3d:8000-FFFF
$1f:0000-7fff $3e:8000-FFFF
$1f:8000-ffff $3f:8000-FFFF

Banks $40-6f : All ROM

Only half of the bank space is authentic, since LoROM ignores SNES A15.

if the MAD-1 decoder chip is used, nothing is mapped to 0000-7FFF in these banks. Otherwise, 0000-7FFF may be a mirror of 8000-FFFF

Note: That tidbit about the MAD-1 is from Neviksti's memmap document. Not verified.

ROM Address SNES Address SNES Mirror
$20:0000-7fff $40:$8000-FFFF $40:0000-7FFF
$20:8000-ffff $41:$8000-FFFF $41:0000-7FFF
$21:0000-7fff $42:$8000-FFFF $42:0000-7FFF
$21:8000-ffff $43:$8000-FFFF $43:0000-7FFF
$22:0000-7fff $44:$8000-FFFF $44:0000-7FFF
$22:8000-ffff $45:$8000-FFFF $45:0000-7FFF
$23:0000-7fff $46:$8000-FFFF $46:0000-7FFF
$23:8000-ffff $47:$8000-FFFF $47:0000-7FFF
$24:0000-7fff $48:$8000-FFFF $48:0000-7FFF
$24:8000-ffff $49:$8000-FFFF $49:0000-7FFF
$25:0000-7fff $4a:$8000-FFFF $4a:0000-7FFF
$25:8000-ffff $4b:$8000-FFFF $4b:0000-7FFF
$26:0000-7fff $4c:$8000-FFFF $4c:0000-7FFF
$26:8000-ffff $4d:$8000-FFFF $4d:0000-7FFF
$27:0000-7fff $4e:$8000-FFFF $4e:0000-7FFF
$27:8000-ffff $4f:$8000-FFFF $4f:0000-7FFF
$28:0000-7fff $50:$8000-FFFF $50:0000-7FFF
$28:8000-ffff $51:$8000-FFFF $51:0000-7FFF
$29:0000-7fff $52:$8000-FFFF $52:0000-7FFF
$29:8000-ffff $53:$8000-FFFF $53:0000-7FFF
$2a:0000-7fff $54:$8000-FFFF $54:0000-7FFF
$2a:8000-ffff $55:$8000-FFFF $55:0000-7FFF
$2b:0000-7fff $56:$8000-FFFF $56:0000-7FFF
$2b:8000-ffff $57:$8000-FFFF $57:0000-7FFF
$2c:0000-7fff $58:$8000-FFFF $58:0000-7FFF
$2c:8000-ffff $59:$8000-FFFF $59:0000-7FFF
$2d:0000-7fff $5a:$8000-FFFF $5a:0000-7FFF
$2d:8000-ffff $5b:$8000-FFFF $5b:0000-7FFF
$2e:0000-7fff $5c:$8000-FFFF $5c:0000-7FFF
$2e:8000-ffff $5d:$8000-FFFF $5d:0000-7FFF
$2f:0000-7fff $5e:$8000-FFFF $5e:0000-7FFF
$2f:8000-ffff $5f:$8000-FFFF $5f:0000-7FFF
$30:0000-7fff $60:$8000-FFFF $60:0000-7FFF
$30:8000-ffff $61:$8000-FFFF $61:0000-7FFF
$31:0000-7fff $62:$8000-FFFF $62:0000-7FFF
$31:8000-ffff $63:$8000-FFFF $63:0000-7FFF
$32:0000-7fff $64:$8000-FFFF $64:0000-7FFF
$32:8000-ffff $65:$8000-FFFF $65:0000-7FFF
$33:0000-7fff $66:$8000-FFFF $66:0000-7FFF
$33:8000-ffff $67:$8000-FFFF $67:0000-7FFF
$34:0000-7fff $68:$8000-FFFF $68:0000-7FFF
$34:8000-ffff $69:$8000-FFFF $69:0000-7FFF
$35:0000-7fff $6a:$8000-FFFF $6a:0000-7FFF
$35:8000-ffff $6b:$8000-FFFF $6b:0000-7FFF
$36:0000-7fff $6c:$8000-FFFF $6c:0000-7FFF
$36:8000-ffff $6d:$8000-FFFF $6d:0000-7FFF
$37:0000-7fff $6e:$8000-FFFF $6e:0000-7FFF
$37:8000-ffff $6f:$8000-FFFF $6f:0000-7FFF

Banks $70-7D : SRAM + ROM

The next banks, Banks $70-7d, are half SRAM, half ROM. Conventional SNES Cart SRAM is max 256 Kbit, or 32Kbyte, $8000 bytes. SRAM has way many many mirrors of its authentic data. Therefore, at largest 'standard' 32KByte SRAM size, the only authentic data is $8000 bytes long, or one SNES SRAM Section worth. The rest are all just mirrors. Smaller SRAMS are even mirrored multiple times in the same bank

SNES Address Type Chip Address
$70:0000-7FFF SRAM0000-7FFF
$70:8000-FFFF ROM $38:0000-7FFF
$71:0000-7FFF SRAM0000-7FFF
$71:8000-FFFF ROM $38:8000-FFFF
$72:0000-7FFF SRAM0000-7FFF
$72:8000-FFFF ROM $39:0000-7FFF
$73:0000-7FFF SRAM0000-7FFF
$73:8000-FFFF ROM $39:8000-FFFF
$74:0000-7FFF SRAM0000-7FFF
$74:8000-FFFF ROM $3a:0000-7FFF
$75:0000-7FFF SRAM0000-7FFF
$75:8000-FFFF ROM $3a:8000-FFFF
$76:0000-7FFF SRAM0000-7FFF
$76:8000-FFFF ROM $3b:0000-7FFF
$77:0000-7FFF SRAM0000-7FFF
$77:8000-FFFF ROM $3b:8000-FFFF
SNES Address
Type Chip Address
$78:0000-7FFF SRAM0000-7FFF
$78:8000-FFFF ROM $3c:0000-7FFF
$79:0000-7FFF SRAM0000-7FFF
$79:8000-FFFF ROM $3c:8000-FFFF
$7a:0000-7FFF SRAM0000-7FFF
$7a:8000-FFFF ROM $3d:0000-7FFF
$7b:0000-7FFF SRAM0000-7FFF
$7b:8000-FFFF ROM $3d:8000-FFFF
$7c:0000-7FFF SRAM0000-7FFF
$7c:8000-FFFF ROM $3e:0000-7FFF
$7d:0000-7FFF SRAM0000-7FFF
$7d:8000-FFFF ROM $3e:8000-FFFF

Banks $7E-7F : System RAM

SNES Address Type
$7e:0000-FFFF System RAM
$7f:0000-FFFF System RAM
7e:0000-1FFF mirrored into SNES 00-3f:0000-1fff, on account of SNES hardware (not cart)

Banks $80-FF : Upper Mirror

Commercial LoRom carts do not wire SNES A23, so everything in SNES banks $80-$FF is a mirror of $00-$7f, with one exception - The System RAM is not repeated. Banks FE-FF hold more SRAM and ROM.
Bank Offset Description
$fe:0000-7FFF SRAM0000-7FFF
$fe:8000-FFFF ROM $3f:0000-7FFF
$ff:0000-7FFF SRAM0000-7FFF
$ff:8000-FFFF ROM $3f:8000-FFFF

Note: You can decide not to mirror banks $80-$FF to get an added upper 32Mbit of cart peripherals mapped. However, for the lower 32Mbit, because Banks 7e-7f are mapped to System RAM, the 32nd Mbit of ROM is not mapped. Don't forget, you don't have to map ROM, you can map anything on the cart with your decoder. If you want to calculate upper ROM offsets like illustrated in the lower banks, just use the lower banks tables and add $80 to the SNES bank byte and add $40 to the ROM bank byte.

7. Other Notes

For ROMS < 32 Mbit, the ROM banks may be further mirrored. For instance, NBA Jam TE is a 24 Mbit LoRom, and will not fill 32Mbit of unique data. This cart in particular mirrors SNES banks $40+ into $60+. You witness similar behavior in other cartridges smaller than 32Mbit.

To Discover Smaller Carts' Mirrored Sections

There are 2 Ways to discover the mirrors:

  1. Reverse the Cart
  2. Use an Emulator Debugger

(1) more accurate; harder; What you will do is analyze the cartridge's logic and do math to understand what gets mirrored. This involves learning/understanding the address decoders on board, I have seen the proprietary MAD-1 and mainstream 74xx139. MAD-1 has been reversed and you can find info on it online.

If you decide to take option 2,The best way to discover a smaller cartridge's mirrors is to use the ROM sections Map, a SNES debuggers' memory viewer, and a Hex Editor opened with the ROM. I use BSNES to do this, and have it compiled for Mac OSX Mountain Lion. Use the ROM Address for correct indexing in your ROM File (Hex Editor) Be cautious of emulation header in the ROM file, or you will have to compensate the additional $200 bytes. You may remove the header; it's typically the first $200 bytes and easy to spot. Removing the header causes no harm to the ROM file and the ROM may be run without an emulation header. Banks that aren't mapped are open bus.

Contact Me

Any questions? Feel free to email.

I am including my fun little brain teaser to accomplish my email rights: ped}}lqrwwlCjpdlo1frp Thats my email address, offset by 3 ascii.