Skip to content

Instantly share code, notes, and snippets.

@AntonioND
Last active April 25, 2025 18:30
Show Gist options
  • Select an option

  • Save AntonioND/d68b0a6b1b4a1722f1a7fda1bbc4a97a to your computer and use it in GitHub Desktop.

Select an option

Save AntonioND/d68b0a6b1b4a1722f1a7fda1bbc4a97a to your computer and use it in GitHub Desktop.
NDS RAM expansion cartridges

NDS RAM expansion cartridges 1.0.0

Note: This document doesn't document all existing devices. Check this instead: https://github.com/blocksds/libnds/blob/2d947e6a6709e646c3366425a840167f2ef5e9c1/source/arm9/peripherals/slot2.c

Author: AntonioND (antonio underscore nd at outlook dot com).

Introduction

There are some GBA cartridges that have RAM chips and that can be inserted in the slot 2 of a Nintendo DS to provide additional RAM for the program running on the console. For example, the Nintendo DS Browser (which is a port of Opera) came with an official RAM expansion pack. There are also several unofficial RAM cartridges that can be used the same way. This document explains how to use the expansion cartridges from homebrew applications.

The documentation doesn't specify the size of any of the RAM chips. It simply autodetects the size by trying to write to the base address, reading from it, checking if the value is the expected one, and retrying after 512 KB. This seems to have been enough, which means that the RAM chips probably don't mirror. If they did, that routine wouldn't work.

Note that I have only been able to test on a SuperCard SD, as it is the only one I own. I have obtained the information below by reading other code and documentation found online, and the purpose of this document is for developers to be able to write new code that can interact with the expansion cartridges, and license it under their own terms, instead of using pre-made libraries.

Important notes:

  • Remember to set the bus owner correctly to access the slot-2. For example, for the ARM9:
sysSetBusOwners(BUS_OWNER_ARM9, BUS_OWNER_ARM9);
  • It is not possible to perform 8-bit writes to the RAM expansion cartridges. It is possible to read 8, 16 or 32 bits, and write 16 or 32 bits.

SuperCard SD

  • Base address: 0x8000000
  • The function to change mode is a series of 16-bit writes to address 0x9FFFFFE:
0xA55A
0xA55A
mode
mode
  • Unlock: The mode value for RAM_RW is 0x5.
  • Lock: The mode value for MEDIA is 0x3.

M3

  • Base address: 0x8000000
  • The function to change mode seems to be a series of 16-bit reads. The read values are discarded:
0x08E00002
0x0800000E
0x08801FFC
0x0800104A
0x08800612
0x08000000
0x08801B66
0x08000000 + (mode << 1)
0x0800080E
0x08000000
0x080001E4
0x080001E4
0x08000188
0x08000188
  • Unlock: The mode value for RAM_RW is 0x00400006
  • Lock: The mode value for MEDIA is 0x00400003

Opera

  • Base address: 0x9000000
  • Unlock: Write 1 to 0x8240000.
  • Lock: Write 0 to 0x8240000.

G6

  • Base address: 0x8000000
  • The function to change mode seems to be a series of 16-bit reads. The read values are discarded:
0x09000000
0x09FFFFE0
0x09FFFFEC
0x09FFFFEC
0x09FFFFEC
0x09FFFFFC
0x09FFFFFC
0x09FFFFFC
0x09FFFF4A
0x09FFFF4A
0x09FFFF4A
0x09200000 + (mode << 1)
0x09FFFFF0
0x09FFFFE8
  • Unlock: The mode value for RAM_RW is 6
  • Lock: The mode value for MEDIA is 3

EZ

Base address: 0x8400000

The code for this cartridge is unusual. There are no lock or unlock functions, but the test routine tries to unlock two different ROM pages. All the described commands work by using 16-bit writes.

All commands sent to the EZ cartridge start by a "command start" routine:

0x9FE0000 = 0xD200
0x8000000 = 0x1500
0x8020000 = 0xD200
0x8040000 = 0x1500

Then, the command body is sent. After the command is sent, the "command end" routine is:

0x9FC0000 = 0x1500

The known commands that can be used as command body are:

  • Set ROM page:
0x9880000 = page
  • Enable NOR write:
0x9C40000 = 0x1500
  • Disable NOR write:
0x9C40000 = 0xD200

The test function sets the ROM page to OS mode (page 0x8000). Then, it enables NOR writing, and checks if address 0x08400000 can be written (and it also checks that address 0x08000000 can't be written). If the conditions are met, this page can be used and no more tests are required.

If that page fails, you need to disable NOR writing, set the ROM page to 352 (why?), and enable NOR writing again. This time, only check if address 0x08400000 can be written.

My proposal would be to run the test command during the first "unlock" run, and save in a variable the ROM page that has worked. Then, we should be able to unlock and unlock the RAM by using the enable/disable NOR write commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment