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.
- I say 40+ when I mean '40 and up'.
- NC = Not Connected
- $8000-byte sections may referred as 32KB sections. $10000-byte sections are 64KB chunks. I may say 64K for short.
- SNES Address range is 3bytes wide. $000000-FFFFFF. This is more easily read as $00:0000 - $FF:0000, which seperates the high bank byte from the the rest of the address with a ':'
- Bank (Byte): a 'Bank' is simply the 3rd byte of a SNES address. It allows us to 'switch' from one 64K section to another, just by incrementing the bank byte alone. SNES Banks are 64K each.
- Mirror: When the same data is mapped to different locations of the memory map, a mirror is produced. The same data can be manipulated from these different locations.
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:
- Address Decoder: Logic that decides what data to provide to SNES. When SNES creates its memory map, it asserts an address, and sometimes asks the cartridge, among other things, to provide data. When it asks the cart for data, it does not specify which data. The Address Decoder's job is to decide, based on the address, what to map.
- SRAM: The Static-Ram memory. This is not on every SNES cart, only the ones with optional RAM. Some SRAM's are accompanied with a Battery (SRAM Bat.), which preserves the data without external power.
- ROM: The program Memory. ROM stands for Read-Only-Memory.
- CIC: Unrelated to the Memory Map. See Wikipedia for details.
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.
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
|Title||ROM Size (Mb)||SRAM Size (Kb)|
|Super Mario World||4||16|
|Tecmo Superbowl III - Final Edition||16||256|
|NBA Jam TE||24||16|
5. Address Line Connections
X = No Connection
Connections are horizontal
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:
- $00:7FFF and $00:8000 - the end of the first chunk into the start of the 2nd chunk
|Table 1 - $7FFF|
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'
- address bit 3 = A3
- A0-A4 = bits 0-4 of the address. That's 5 bits total
- Now you know that, I will start prefixing with A now
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:
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.
Then we increment it to $010000
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 MapBanks
Banks $00-3f : System Area
|$4000-$43FF||Internal CPU Registers|
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|
Banks $70-7D : SRAM + ROMThe 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
Banks $7E-7F : System RAM
Banks $80-FF : Upper MirrorCommercial 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.
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:
- Reverse the Cart
- 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 MeAny questions? Feel free to email.
I am including my fun little brain teaser to accomplish my email rights:
Thats my email address, offset by 3 ascii.