CC5X C compiler for PICmicro

Nds Decompiler

Let us walk through a real example. Assume you extracted arm9.bin from a commercial ROM using ndstool.

Step 1: Identify the load address The header at offset 0x20 says the ARM9 entry point. Usually 0x02000000 or 0x03700000 (for DLDI homebrew).

Step 2: Create a new Ghidra project

Step 3: Define memory regions Add RAM: 0x02000000 to 0x0203FFFF (256KB ITCM? No – DS has 4MB main RAM). Actually, DS ARM9 main RAM is 0x02000000 to 0x023FFFFF (4MB). Add VRAM banks if needed.

Step 4: Auto-analyze – Ghidra will find code entry points. Use the Decompiler window.

Step 5: Interpret the output – For a simple function that sets the display mode, Ghidra might give:

void setMode3(void) 
  DAT_04000000 = 0x23;   // hand-correct to DISPCNT = MODE_3 

This is not original source, but it is functionally equivalent.

This is where the actual "decompilation" happens. nds decompiler

Example of what decompiled code looks like (pseudo-C):

void FUN_02001234(void) 
    // This is likely a sprite initialization function
    (*(volatile u32 *)0x4000000) = 0x10000; 
    (*(volatile u32 *)0x4000004) = 0x0;
    return;

Decompiling a Nintendo DS game is the process of converting the machine code (binary) stored on the cartridge back into a human-readable format (such as C or C++ source code). This is a reverse engineering process used for game preservation, creating fan translations, or fixing bugs in old games.

It is important to note that you cannot simply click a button and get the original source code. The process requires significant manual effort.

The Nintendo DS (NDS) is a dual-screen ARM-based handheld console released in 2004. Decompilation in the context of NDS games refers to the process of translating compiled machine code (ARM9, ARM7, or Thumb binaries) back into a high-level language, ideally human-readable C or C++ code.

Unlike simple disassembly (which gives assembly mnemonics), a decompiler attempts to recover structure: loops, conditionals, functions, variable names, and data types.

However, true full-decompilation of arbitrary NDS ROMs remains an unsolved automation problem. Most successful efforts are semi-manual and game-specific (e.g., Pokémon Diamond, Super Mario 64 DS).


Summary

What it does well

Common limitations

Who should use it

Practical tips

Verdict (concise)

Related search suggestions (Function invoked)


Goal: Decompile a function that sets up 3D rendering on ARM9. Let us walk through a real example

Step 1 – Locate function in disassembly (Ghidra):

08001234:  push r4, lr
08001236:  mov  r0, #0x4000000
0800123a:  mov  r1, #0x1000
0800123e:  strh r1, [r0, #0x0]   ; DISPCNT

Step 2 – Decompile (Ghidra output):

void FUN_08001234(void) 
  *(uint16_t*)0x4000000 = 0x1000;
  return;

Step 3 – Manual refinement:

#include "nds/arm9/display.h"  // manual header
void enableBG3D() 
    DISPCNT = DISPLAY_BG3_ACTIVE 

Step 4 – Iterate – rename function, propagate types, match to NitroSDK.


If you want to “decompile” an NDS game:


| Challenge | Description | |-----------|-------------| | Thumb/ARM interworking | Decompilers often misalign control flow at mode switches | | Inlined assembly | SDK macros use inline asm for speed; decompiler produces gibberish | | Overlays | Code loaded at runtime into same address space – static analysis misses cross-overlay calls | | Custom memory maps | NDS has 8+ distinct memory regions (Main RAM, VRAM, Shared WRAM, etc.) – pointers ambiguous | | Register banking | ARM9 has banked registers for IRQ/Supervisor modes – decompiler sees only user mode | | Binary differencing | Matching decompiled code to known SDK versions requires signature scanning |


End line