Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Division by zero in /usr/share/web/joat/webshare/ds/index.php on line 1101

Warning: Cannot modify header information - headers already sent by (output started at /usr/share/web/joat/webshare/ds/index.php:1101) in /usr/share/web/joat/webshare/ds/index.php on line 885
NDSTech Wiki : Flash Cartridges browse
Flash Cartridges

Menu

Getting Started

System Information

Misc

Visoly / Flash-Advance

The older-style non-turbo cartridges contain a single intel 28F Flash, while the newer turbo cartridges contain a pair of chips interleaved.

TypeFlashRAMNotes
64M1x 28F640J3A (120ns)128 KB3 bank bits, cannot reliably do 3/1 waits
Turbo 64M2 x 28F320J3A (110ns)256 KBOnly has 3 bank bits
Turbo 128M2 x 28F640J3A (120ns)256 KByteOnly has 3 bank bits
FA Pro 64M2 x 28F320J3A (110ns)256 KByteAlso supports 4 kbit eeprom
FA Pro 128M2 x 28F640J3A (120ns)256 KByteAlso supports 4 kbit eeprom
FA Pro 256M2 x 28F640J3A (120ns)256 KByteAlso supports 4 kbit eeprom
FA Xtreme 512M/1G2 or 4 x 28F256K3256 KByte 

Notes:

  • All carts use Intel flash parts.
  • All of the 256 KB SRAM carts use a NEC D442000LGU chip.
  • None of the carts support the 64 kbit eeprom type
  • The three bank bits carts only support the 8 MB, 4 MB, and 256 KB bits (see below for more information).
 
VisolyCommand(uint32 address, uint16 data, uint16 count)
  for ( ; count > 0; count--)
    GBA_CART[addr << 1] = data;

VisolyUnlock(yes, it really is this stupid!)
  VisolyCommand(0x987654, 0x5354, 1)
  VisolyCommand(0x012345, 0x1234, 500)
  VisolyCommand(0x007654, 0x5354, 1)
  VisolyCommand(0x012345, 0x5354, 1)
  VisolyCommand(0x012345, 0x5678, 500)
  VisolyCommand(0x987654, 0x5354, 1)
  VisolyCommand(0x012345, 0x5354, 1)
  VisolyCommand(0x765400, 0x5678, 1)
  VisolyCommand(0x013450, 0x1234, 1)
  VisolyCommand(0x012345, 0xABCD, 500)
  VisolyCommand(0x987654, 0x5354, 1)

// Disable the write-protection on the Flash ROM
VisolyUnlockFlash
  VisolyUnlock
  VisolyCommand(0xF12345, 0x9413, 1)

// Select which bank of SRAM is visible (64 KB each, 4 or 8 implemented)
VisolySetSRAMBank(bank)
  VisolyUnlock
  VisolyCommand(0xA12345, bank & 7, 1)

// returns true if the offset is valid
// for old-style cartridges
bool VisolySetFlashBaseAddress(offset)
  if (offset & 0xFF3F7FFF) return false

  base = ((offset >> 22) & 3) | ((offset >> 12) & 8)
  VisolyUnlock
  VisolyCommand(0xB5AC97, base, 1)

  return true

// returns true if the offset is valid
// for new-style cartridges
bool VisolySetFlashBaseAddress(offset)
  if (offset & 0xFE007FFF) return false

  base = ((offset >> 22) & 3) | ((offset >> 22) & 4) | ((offset >> 12) & 0x3F8)
  VisolyUnlock
  VisolyCommand(0xB5AC97, base, 1)

  return true

The Flash offset register is a bit funky, and only bits 0, 1, and 3 are implemented on the older cartridges. Format of the register is shown below:

15..109876543210
-2 MB1 MB512 KB256 KB128 KB64 KB32 KB16 MB8 MB4 MB

Thanks to Jeff Frohwein and Reiner Ziegler


GBA Movie Player

Components

  • FlashROM, SST39VF400A 256Kx16 (0x278000BF) or SST39VF800A 512Kx16 (0x278100BF)
  • CPLD, Actel eX64, 64 pin TQFP

Pinout

GBA Aflash Ainvertedpin
01016
11115
21214
3818
4907
57018
66019
75120
82023
93122
104121
110125
121124
13---
14---
15---
161303
171402
181501
1916048
2017017
2118016 (512K x 16 only)

Registers

Data registerMP_DATA0x09000000
Error registerMP_REG_ERR0x09020000
Sector #MP_REG_SEC0x09040000
LBA byte 1MP_REG_LBA10x09060000
LBA byte 2MP_REG_LBA20x09080000
LBA byte 3MP_REG_LBA30x090A0000
0xE0 | LBA byte4MP_REG_LBA40x090C0000
Command registerMP_REG_CMD0x090E0000
Status registerMP_REG_STS0x098C0000

Unlock sequence

Unlocking is required to read offset >=0x200.

A short unlock sequence that works in most cases can be performed by reading these offsets in order: 0x0134,0x00D4,0x0144,0x00EC,0x01E4,0x0188,0x01F4,0x01D4


M3 CF/SD

CompactFlash addresses

Data registerMP_DATA0x08800000
Error registerMP_REG_ERR0x08820000
Sector #MP_REG_SEC0x08840000
LBA byte 1MP_REG_LBA10x08860000
LBA byte 2MP_REG_LBA20x08880000
LBA byte 3MP_REG_LBA30x088A0000
0xE0 | LBA byte4MP_REG_LBA40x088C0000
Command registerMP_REG_CMD0x088E0000
Status registerMP_REG_STS0x080C0000

M3 mode switching:

 
static u16 M3_readHalfword (u32 addr) {
   return *((vu16*)addr);
}

void M3_changeMode (u32 mode) {

   M3_readHalfword (0x08e00002);
   M3_readHalfword (0x0800000e);
   M3_readHalfword (0x08801ffc);
   M3_readHalfword (0x0800104a);
   M3_readHalfword (0x08800612);
   M3_readHalfword (0x08000000);
   M3_readHalfword (0x08801b66);
   M3_readHalfword (0x08000000 + (mode << 1));
   M3_readHalfword (0x0800080e);
   M3_readHalfword (0x08000000);

   if ((mode & 0x0f) == 4) {   // unlock ROM addr >= 0x200
      M3_readHalfword (0x080001e4);
      M3_readHalfword (0x080001e4);
      M3_readHalfword (0x08000188);
      M3_readHalfword (0x08000188);
   } else {
      M3_readHalfword (0x09000000);
   }

}

// Values for changing mode
 #define M3_MODE_ROM 0x00400004
 #define M3_MODE_MEDIA 0x00400003
 #define M3_MODE_RAM_R 0x00400002
 #define M3_MODE_RAM_RW 0x00400006 // read-write access 


(Thanks to Chishm)

RAM R/W mode can also be enabled by writing 0xAA55 to 0x09FFEFFE.


G6

G6 SDRAM can be made writable by writing 0xAA55 to 0x09FFFFFE.


General CF information

CF card status:

  • Inserted: 0x50
  • Removed: 0x00
  • Ready: 0x58
  • DRQ: 0x08
  • Busy: 0x80

CF card commands:

  • LBA: 0xE0
  • Read: 0x20
  • Write: 0x30

Initialize CF by writing 0x50 to the status register: MP_REG_STS = 0x50.

Thanks to DarkFader, Chishm, and MightyMax for info on the GBA MP and M3.


SuperCard (CF version)

Components:

  • Lattice ispMACH LC4128V : CPLD (Mach4000 family)
  • HY57V561620CTP-H (Hynix): 256 Mbit SDRAM, 3.3V, PC133-CL3
  • M5M5V208AKV (Mitsubishi): 2 Mbit CMOS SRAM , 2.7-3.6V, 70ns
  • 29LV400TC-90PFTN (Fairchild also avail. from Fujitsu): 4Mbits FLASH, 90ns, 3V

Note: Untested, based on code posted to forum. Credit due to the unknown author of 20051024113435206.zip

NameDefineAddressSize
Sector bufferSC_CF_DATA0x09000000512
Unlock registerSC_UNLOCK0x09FFFFFE2
Sector countSC_CF_SECTOR_COUNT0x090400002
LBA byte 1SC_CF_LBA10x090600002
LBA byte 2SC_CF_LBA20x090800002
LBA byte 3SC_CF_LBA30x090A00002
0xE0 | LBA byte4SC_CF_LBA40x090C00002
Command registerSC_CF_CMD0x090E00002
Status registerSC_CF_STATUS0x099C00002
Status registerSC_CF_STATUS_L0x099C00001

The status register can be accessed as both a byte or halfword, the others all seem to be treated as halfwords (even though only 8 bits of data are stored in each). I don't have a supercard to test this for sure. Thus, you can't read more than 255 sectors at a time either (possibly 256 if 0 is stored?).

Unlike the M3, either the supercard appears to have a 512 byte sector buffer (unlikely), rather than a one byte FIFO, or the daft code just makes use of address mirroring to read the one byte FIFO at 512 addresses (more likely).

Format of the Supercard unlock register:

15..3?
2Enable SDRAM
1Enable CF / SD
0Always 1 after 0x5AA5

You write 0xA55A twice, then write 0x5 (enable SDRAM), 0x3 (enable CF / SD), or 0x1 (disable SDRAM, presumably also disable CF/SD) twice.

I'm going to take a wild guess and say that enabling both SDRAM and CF/SD at the same time is a bad idea. Also, on the cartridges with both SD and CF, are there two seperate bits to enable them?

 
Supercard_Unlock:
  SC_UNLOCK = 0xA55A
  SC_UNLOCK = 0xA55A
  SC_UNLOCK = 0x0003
  SC_UNLOCK = 0x0003

Supercard_IsCFInserted
  SC_CF_STATUS = 0x0050
  nop
  return (SC_CF_STATUS_L == 0x50)

Supercard_CFCommand(command, address, count)
  while ((SC_CF_STATUS_L & 0xC0) != 0x40) ;
  SC_CF_SECTOR_COUNT = count;
  SC_CF_LBA1 = address & 0xFF;
  SC_CF_LBA2 = (address>>8) & 0xFF;
  SC_CF_LBA3 = (address>>16) & 0xFF;
  SC_CF_LBA4 = ((address>>24) & 0xFF) | 0xE0;
  SC_CF_CMD = command;


// delay for a little bit, they run a loop of a few cycles for
// 16 iterations.  The overhead involved in a call to DelayLoop
// takes nearly that long, not counting the delay itself, so this
// can probably be reduced.
Delay16
  DelayLoop(0x10)

// address is the LBA address on the CF card
// count is the number of 512 byte sectors
// destination is the memory address to store to
Supercard_ReadSectors(address, count, destination)
  Supercard_CFCommand(0x20, address, count)
  Delay16
  for each sector do
    while ((SC_CF_STATUS & 0x88) == 0x80) ;
    Copy 512 bytes from SC_CF_DATA to destination and advance destination
  end;


// source is the memory address to read from
// address is the LBA address on the CF card
// count is the number of 512 byte sectors
Supercard_WriteSectors(source, address, count)
  Supercard_CFCommand(0x30, address, count)
  Delay16
  for each sector do
    while ((SC_CF_STATUS & 0x88) == 0x80) ;
    Copy 512 bytes from source to SC_CF_DATA and advance destination
  end;
  while ((SC_CF_STATUS & 0x80) != 0) ;


Supercard (SD version)

Components

  • FlashROM, 512KB, Fairchild 29LV400TV-80PFTN
  • SDRAM, 32 MBytes, Hynix HY57V561620CT-H
  • SRAM, 256 KBytes, Samsung KM68V2000LTGI-8L
  • CPLD, Lattice ispMACH LC4128V 75T100-10I
  • Oscillator, 50 MHz
  • JTAG connections at bottom cart edge

Unlock register

15?
14Should be 1 ?
13?
12some bankswitch?
9..11?
8some bankswitch?
7?
5..6Should be 0 ?
40=select ROM, 1=select SD
3?
2SDRAM: 0=write protect, 1=allow writes
1?
00=select ROM or SD, 1=select SDRAM

(bits are manually tested without looking to any code)

To set a new value, write 0xA55A to this register twice, then write the desired value twice.

Below code is translated from some whack assembly, so it might contain bugs. Credit due to the unknown author of 20051024113435206.zip

 
SC_SD_COMMAND 0x09800000
SC_SD_DATA    0x09000000
SC_SD_READ    0x09100000

////////////////////////////////////////////////////////////

void sd_data_write_s(uint16 * buffer, uint16 * crc16buff)
  // Wait until it's idle
  while (!(SC_SD_DATA & 0x100)) ;
  r3 = SC_SD_DATA;

  // start bit
  SC_SD_DATA = 0

  r5 = 512;
  do {
    r3 = *buffer++
    r3 = r3 + (r3 << 20)
    r4 = r3 << 8
    SC_SD_DATA32 = r3
    SC_SD_DATA32 = r4
  } while (--r5 > 0);

  if (crc16buff) {
    r0 = crc16buff
    r1 = 0
    r5 = 8
    goto the copy loop again just above
  }

  // end bit
  SC_SD_DATA = 0xFF
  while (SC_SD_DATA & 0x100) ;
  r3 = SC_SD_DATA32
  r4 = SC_SD_DATA32

////////////////////////////////////////////////////////////

sd_data_read_s(uint16 * destination)
  while (SC_SD_READ & 0x100) ; // wait for the start bit to clear

  for (i = 0; i < 256; i++)
    r3 = SC_SD_READ32
    r4 = SC_SD_READ32
    r3 = r4 >> 16
    *destination++ = r4 >> 16;

  // Read (and throw away) the CRC-16 (2 bytes)
  r3 = SC_SD_READ32
  r4 = SC_SD_READ32
  r3 = SC_SD_READ32
  r4 = SC_SD_READ32

  // Read (and throw away) the end bit
  r3 = SC_SD_READ


////////////////////////////////////////////////////////////

void sd_com_crc16_s(uint8 * buffer, uint16 num, uint8 * crc16buff)
  r3 = r4 = r5 = r6 = 0

  r7 = 0x80808080
  r8 = 0x1021
  r1 = r1 << 3

  do {
    if (r7 & 0x80) r2 = *buffer++

    r3 = r3 << 1
    if (r3 & 0x10000) r3 = r3 ^ r8
    if (r2 & (r7>>24)) r3 = r3 ^ r8

    r4 = r4 << 1  
    if (r4 & 0x10000) r4 = r4 ^ r8
    if (r2 & (r7>>25)) r4 = r4 ^ r8

    r5 = r5 << 1
    if (r5 & 0x10000) r5 = r5 ^ r8
    if (r2 & (r7>>26)) r5 = r5 ^ r8

    r6 = r6 << 1
    if (r6 & 0x10000) r6 = r6 ^ r8
    if (r2 & (r7>>27)) r6 = r6 ^ r8

    r7 = (r7 >> 4) | (r7 << 28)

    r1 -= 4;
  } while (r1);


  mov  r2 = crc16buff
  r8 = 16
  do {
    r7 = r7 << 4
    if (r3 & 0x8000) r7 = r7 | 8
    if (r4 & 0x8000) r7 = r7 | 4
    if (r5 & 0x8000) r7 = r7 | 2
    if (r6 & 0x8000) r7 = r7 | 1

    r3 = r3 << 1
    r4 = r4 << 1
    r5 = r5 << 1
    r6 = r6 << 1

    r8--;
    if (r8 & 1) *crc16buf++ = r7
  } while (r8);

////////////////////////////////////////////////////////////

sd_crc7_s(uint8 * buffer, uint16 count)
  r3 = 0
  r4 = 0x80808080

  r1 = count*8
  do {
    if (r4 & 0x80) r2 = *buffer++
    r3 = r3 << 1

    if (r3 & 0x80) r3 ^= 9;
    if (r2 & (r4>>24)) r3 ^= 9;
    r4 = (r4 >> 1) | (r4 << 31)
  } while (--r1 > 0);  

  return (r3 << 1) + 1

////////////////////////////////////////////////////////////

sd_com_read_s
  while (SC_SD_COMMAND & 1) ; // wait for start bit to clear
  do r1--; while (r1);


////////////////////////////////////////////////////////////

sd_com_write_s(uint8 * buffer, uint32 count):
  while (!(SC_SD_COMMAND & 1)) ; // wait for start bit to set
  temp = SC_SD_COMMAND;          // throwaway read


  do {
    temp = *buffer++
    temp = temp + (temp << 17)
    r4 = temp<<2
    r5 = r4<<2
    r6 = r5<<2
    SC_SD_COMMAND = temp
    SC_SD_COMMAND = r4
    SC_SD_COMMAND = r5
    SC_SD_COMMAND = r6
  } while (--count)


////////////////////////////////////////////////////////////

send_clk(count)
  do {
    temp = SC_SD_COMMAND; // throwaway read
  } while (--count)


////////////////////////////////////////////////////////////

// num not used!!!!!
void SDCommand(uint8 command, uint8 num, uint32 sector)
  uint8 buffer[6];

  buffer[0] = command | 0x40;
  buffer[1] = sector >> 24;
  buffer[2] = (sector >> 16) & 0xFF;
  buffer[3] = (sector >> 8) & 0xFF;
  buffer[4] = sector & 0xFF;
  buffer[5] = sd_crc7_s((u32)databuff, 5);

  sd_com_write_s(databuff, 6);

////////////////////////////////////////////////////////////


void ReadSector(u16 *buff,u32 sector,u8 readnum)
{
  SDCommand(18, 0, sector << 9); 

  for (j = 0; j < readnum; j++)
    sd_data_read_s((u32)buff+j*512);

  SDCommand(12, 0, 0); 
  get_resp();
  send_clk(0x10);
}


////////////////////////////////////////////////////////////

get_resp:
  sd_com_read_s(r0 = ?, r1 = 6)

////////////////////////////////////////////////////////////

void WriteSector(uint16 * buffer, uint32 sector, uint8 writenum)
{
  register u16 i,j;
  u16 crc16[5];
  i=writenum;

  sectno<<=9;

  SDCommand(25,0,sector); 
  get_resp();
  send_clk(0x10); 

  for (j=0;j<i ; j++)
  {
    sd_crc16_s((u32)(u32)buff+j*512,512,(u32)crc16);
    sd_data_write_s((u32)buff+j*512,(u32)crc16);
    send_clk(0x10); 
  }
  SDCommand(12,0,0); 
  get_resp();
  send_clk(0x10);
  while((*(u16*)sd_dataadd &0x0100)==0);
}

////////////////////////////////////////////////////////////

MemoryCard_IsInserted:
  return (SC_SD_COMMAND & 0x0300 == 0);


NeoFlash (same as XG Flash v2 ?)

Unlock sequence:

 
  0x09555554:16 = 0xAAAA
  0x08AAAAAA:16 = 0x5555

Any read to the AD mux bus will disable the 'unlock'.

The following registers are on the compatible bus (0x0E00xxxx on the GBA, 0x0A00xxxx on the DS), and are thus 8 bits wide.

Save memory type register (0xFFF8)

76543210
01111Mode

Mode:

  • 000: 32 KB SRAM
  • 001: 64 KB Flash
  • 010: EEPROM
  • 101: 128 KB Flash (bankswitched with 0xB0)
  • dunno about other values

Flash offset register (0xFFFE)

76543210
A23A22A21A20A19A18A17A16

Save memory offset register (0xFFFF)

76543210
FixedSharedSRAMEEPROM
1H2H1H0A15A15A14A13

Notes:

  • The high address bits are shared for all 3 types of memory
  • EEPROM specific bits are only used for EEPROM
  • SRAM A15 should be zero when using Flash

The flash chip (Intel Z412LA35A on the NeoFlash cart) can be erased/written after being unlocked. If anyone has chip names for Xg1 / Xg2 carts, I'd appreciate the information.


EZFlash III

The EZF-3 contains five chips:

  • 32 Mbit NOR flash (mapped in at boot-time)
  • 128 Mbit PSRAM
  • 256 Mbit NOR flash
  • 1 Gbit NAND flash
  • 2 Mbit SRAM

Memory map in OS mode:

  • 0x08000000: 32 MBit NOR Flash
  • 0x08400000: 128 MBit PSRAM
  • 0x08800000: 64 MBit window into 256 MBit NOR flash (see ROM bank reg)
  • 0x08C00000: ?
  • 0x08FFE000: NAND flash interface

Memory map in game mode:

  • 256 MBit NOR Flash
  • 128 MBit PSRAM
  • 32 MBit NOR Flash

The offset into these for 0x08000000 is written to using the ROM page control register (e.g. if you wrote 0 for the page there, the 256 MBit of NOR would fill the cartridge bus, but writing 256 places the PSRAM in the space, ***I think***).

 
// Each page is 1 Mbit
void SetRomPage(uint16 page) {
  *(u16 *)0x9FE0000 = 0xD200;
  *(u16 *)0x8000000 = 0x1500;
  *(u16 *)0x8020000 = 0xD200;
  *(u16 *)0x8040000 = 0x1500;

  *(u16 *)0x9880000 = page;

  *(u16 *)0x9FC0000 = 0x1500;
}

//////////////////////////////////////////////////////////////////////

// Picks a page of SRAM to map in at 0x0E000000(gba) / 0x0A000000(ds)
// Each page is 32 KB
void SetRampage(uint16 page)
{
  *(u16 *)0x9FE0000 = 0xD200;
  *(u16 *)0x8000000 = 0x1500;
  *(u16 *)0x8020000 = 0xD200;
  *(u16 *)0x8040000 = 0x1500;

  *(u16 *)0x9C00000 = page;

  *(u16 *)0x9FC0000 = 0x1500;
}

//////////////////////////////////////////////////////////////////////

// Enables writes to Flash?
void OpenWrite()
{
  *(u16 *)0x9FE0000 = 0xD200;
  *(u16 *)0x8000000 = 0x1500;
  *(u16 *)0x8020000 = 0xD200;
  *(u16 *)0x8040000 = 0x1500;

  *(u16 *)0x9C40000 = 0x1500;

  *(u16 *)0x9FC0000 = 0x1500;
}

//////////////////////////////////////////////////////////////////////

// Disables writes to Flash?
void CloseWrite()
{
  *(u16 *)0x9FE0000 = 0xD200;
  *(u16 *)0x8000000 = 0x1500;
  *(u16 *)0x8020000 = 0xD200;
  *(u16 *)0x8040000 = 0x1500;

  *(u16 *)0x9C40000 = 0xD200;

  *(u16 *)0x9FC0000 = 0x1500;
}

//////////////////////////////////////////////////////////////////////

void SetNandControl(uint16 control)
{
  *(u16 *)0x9FE0000 = 0xD200;
  *(u16 *)0x8000000 = 0x1500;
  *(u16 *)0x8020000 = 0xD200;
  *(u16 *)0x8040000 = 0x1500;

  *(u16 *)0x9400000 = control;

  *(u16 *)0x9fc0000 = 0x1500;
}


ROM page control register:

151: OS mode, 0: Game mode
14Dunno
13..12Which 64 Mbit bank of NOR appears at 0x09400000 .. 0x09C00000
11..9Dunno, could be more page register
8..0Page register (in 1 MBit chunks)

Bits 13 and 12 do not work in game mode.

NAND interface:

  • 0xFFFFF0: WRITE COMMAND
  • FFFFF0: WRITE ADDRESS
  • 0xFFE000 TO 0xFFEFFF: R/W DATA

NAND control register format:

15..2?
10: 8 bit mode, 1: 16 bit mode
00: Disabled, 1: Enabled

Thanks to Davr and DarkFader for information on the EZF-3.


Thanks to pepsiman for the info on enabling SDRAM for M3 / G6 / Supercard.

Any information on the EZFA, F2A, and XgFlash 1 carts would be appreciated (and any others I'm not thinking of).

Recent Changes (All) | Edit SideBar

Page last modified on August 15, 2006, at 11:07 AM
Edit Page | Page History
Everything done on this project is for the sole purpose of writing interoperable software under Sect. 1201 (f) Reverse Engineering exception of the DMCA.
This site is not affiliated with Nintendo in any manner. Nintendo DS © 2004 Nintendo. TM and ® are trademarks of Nintendo.
Powered by PmWiki