ARM programming for the Nintendo DS
This page is Under Construction....

The Nintendo DS is the sucessor to the Gameboy advance, based on the ARM - the NDS uses an ARM9 as it's main processor - with an ARM7 secondary processor - which is used for backwards compatibility with the Gameboy Advance.

Tech Specs
CPU 66 MHZ ARM9 + 33 MHZ ARM7TDMI
Memory 4MB - 656k VRAM
Resolution 256x192 x 2 screens - 32K colors
3D 1x 3D screen 1x 2D screen
Sound 4 channel + 2xDMA
The 3 generations of the GBA

If you want to learn ARM get the Cheatsheet! it has all the ARM7 commands, it covers the commands, and options like Bitshifts and conditions as well as the bytecode structure of the commands!

ARM Hello World Series

Hello World on the Nintendo DS - ARM Assembly Lesson H3

ARM Platform Specific Lessons

Lesson P4 - Bitmap graphics and Palette definitions on the Nintendo DS (16 bit - 32768 colors) [NDS]
Lesson P5 - Joypad & Pen on the GBA / NDS ... Key reading on Risc OS [NDS] [GBA] [ROS]
Lesson P7 - Sound on the Nintendo DS [NDS]
Lesson P8 - 16 color Tilemap on the Gameboy Advance and Nintendo DS! [GBA] [NDS]
Lesson P9 - Hardware Sprites on the Gameboy Advance and Nintendo DS! [GBA] [NDS]
Graphics hardware
The Nintendo DS has two screens, and two 'Graphics engines'... each Graphics engine can drive either screen, but only one screen at a time.

Graphics Engine A is the most powerful... it can do GBA style 2D, 3D or directly show RAM to screen.... it can also do screen capture.
Graphics Engine B is more limited, it can only do GBA style 2D*

In these tutorials, we'll use Graphics Engine A for the top screen, showing Direct Ram.... we'll use Graphics Engine B in Apline (Rotate & Scale) mode, showing an area of memory onscreen with Background Layer 2...

Despite the different setup, the result is both screens are memory mapped in -bABBBBBGGGGGRRRRR - with 1 bit of Alpha, and 5 bits of Red,Green and Blue (The Alpha is unused for the top screen - as it's showing direct ram)

* it's not possible to do 3D on both screens - however Engine A can capture 3D, and show that as an image on Engine B - halving the framerate, but giving apparent 3D on both screens!

Technical Resources
GBATEK - complete documentation on the GBA and NDS - this tutorial would not be possible without the content on their site!

Memory Map
Address Purpose
00000000h Instruction TCM (32KB) (not moveable) (mirror-able to 1000000h)
0xxxx000h Data TCM (16KB) (moveable)
02000000h Main Memory (4MB)
03000000h Shared WRAM (0KB, 16KB, or 32KB can be allocated to ARM9)
04000000h ARM9-I/O Ports
05000000h Engine A Standard BG Palette (512 bytes)
05000200h Engine A Standard OBJ Palette (512 bytes)
05000400h Engine B Standard BG Palette (512 bytes)
05000600h Engine B Standard OBJ Palette (512 bytes)
06000000h VRAM - Engine A, BG VRAM (max 512KB)
06200000h VRAM - Engine B, BG VRAM (max 128KB)
06400000h VRAM - Engine A, OBJ VRAM (max 256KB)
06600000h VRAM - Engine B, OBJ VRAM (max 128KB)
06800000h VRAM - "LCDC"-allocated (max 656KB)
07000000h Engine A OAM (1024 bytes)
07000400h  
Engine B OAM (1024 bytes)
08000000h GBA Slot ROM (max 32MB)
0A000000h GBA Slot RAM (max 64KB)
FFFF0000h ARM9-BIOS (32KB) (only 3K used)

Ports (ARM9 side)
Category Address Name Description
DispA 4000000h DISPCNT LCD Control (RW)
DispA 4000004h
2D Engine A+B - DISPSTAT - General LCD Status (RW) (Bit 0=VBlank)
DispA 4000006h
2D Engine A+B - VCOUNT - Vertical Counter (Read only)
DispA 4000008h
2D Engine A (same registers as GBA, some changed bits)
DispA 4000008h BG0CNT BG0 Control
DispA 400000Ah BG1CNT BG1 Control
DispA 400000Ch BG2CNT BG2 Control
DispA 400000Eh BG3CNT BG3 Control
DispA 4000010h BG0HOFS BG0 X-Offset
DispA 4000012h BG0VOFS BG0 Y-Offset
DispA 4000014h BG1HOFS BG1 X-Offset
DispA 4000016h BG1VOFS BG1 Y-Offset
DispA 4000018h BG2HOFS BG2 X-Offset
DispA 400001Ah BG2VOFS BG2 Y-Offset
DispA 400001Ch BG3HOFS BG3 X-Offset
DispA 400001Eh BG3VOFS BG3 Y-Offset
DispA 4000020h BG2PA BG2 Rotation/Scaling Parameter A (dx)
DispA 4000022h BG2PB BG2 Rotation/Scaling Parameter B (dmx)
DispA 4000024h BG2PC BG2 Rotation/Scaling Parameter C (dy)
DispA 4000026h BG2PD BG2 Rotation/Scaling Parameter D (dmy)
DispA 4000028h BG2X BG2 Reference Point X-Coordinate
DispA 400002Ch BG2Y BG2 Reference Point Y-Coordinate
DispA 4000030h BG3PA BG3 Rotation/Scaling Parameter A (dx)
DispA 4000032h BG3PB BG3 Rotation/Scaling Parameter B (dmx)
DispA 4000034h BG3PC BG3 Rotation/Scaling Parameter C (dy)
DispA 4000036h BG3PD BG3 Rotation/Scaling Parameter D (dmy)
DispA 4000038h BG3X BG3 Reference Point X-Coordinate
DispA 400003Ch BG3Y BG3 Reference Point Y-Coordinate
DispA 4000040h WIN0H Window 0 Horizontal Dimensions
DispA 4000042h WIN1H Window 1 Horizontal Dimensions
DispA 4000044h WIN0V Window 0 Vertical Dimensions
DispA 4000046h WIN1V Window 1 Vertical Dimensions
DispA 4000048h WININ Inside of Window 0 and 1
DispA 400004Ah WINOUT Inside of OBJ Window & Outside of Windows
DispA 400004Ch MOSAIC Mosaic Size
DispA 400004Eh - Not used
DispA 4000050h BLDCNT Color Special Effects Selection
DispA 4000052h BLDALPHA Alpha Blending Coefficients
DispA 4000054h BLDY Brightness (Fade-In/Out) Coefficient
DispA 4000056h - Not used
DispA 4000060h
DISP3DCNT - 3D Display Control Register (R/W)
DispA 4000064h
DISPCAPCNT - Display Capture Control Register (R/W)
DispA 4000068h
DISP_MMEM_FIFO - Main Memory Display FIFO (R?/W)
DispA 400006Ch
2D Engine A - MASTER_BRIGHT - Master Brightness Up/Down
DMA/Key 40000B0h
DMA Channel 0..3
DMA/Key 40000E0h
DMA FILL Registers for Channel 0..3
DMA/Key 4000100h
Timers 0..3
DMA/Key 4000130h
KEYINPUT (Gameboy Advance Type Keys UDLR AB Sel Start)
DMA/Key 4000132h
KEYCNT
IPC/Rom 4000180h
IPCSYNC - IPC Synchronize Register (R/W)
IPC/Rom 4000184h
IPCFIFOCNT - IPC Fifo Control Register (R/W)
IPC/Rom 4000188h
IPCFIFOSEND - IPC Send Fifo (W)
IPC/Rom 40001A0h
AUXSPICNT - Gamecard ROM and SPI Control
IPC/Rom 40001A2h
AUXSPIDATA - Gamecard SPI Bus Data/Strobe
IPC/Rom 40001A4h
Gamecard bus timing/control
IPC/Rom 40001A8h
Gamecard bus 8-byte command out
IPC/Rom 40001B0h
Gamecard Encryption Seed 0 Lower 32bit
IPC/Rom 40001B4h
Gamecard Encryption Seed 1 Lower 32bit
IPC/Rom 40001B8h
Gamecard Encryption Seed 0 Upper 7bit (bit7-15 unused)
IPC/Rom 40001BAh
Gamecard Encryption Seed 1 Upper 7bit (bit7-15 unused)
Ram/IRQ 4000204h
EXMEMCNT - External Memory Control (R/W)
Ram/IRQ 4000208h
IME - Interrupt Master Enable (R/W)
Ram/IRQ 4000210h
IE
Ram/IRQ 4000214h
IF
Ram/IRQ 4000240h
VRAMCNT_A - VRAM-A (128K) Bank Control (W)
Ram/IRQ 4000241h
VRAMCNT_B - VRAM-B (128K) Bank Control (W)
Ram/IRQ 4000242h
VRAMCNT_C - VRAM-C (128K) Bank Control (W)
Ram/IRQ 4000243h
VRAMCNT_D - VRAM-D (128K) Bank Control (W)
Ram/IRQ 4000244h
VRAMCNT_E - VRAM-E (64K) Bank Control (W)
Ram/IRQ 4000245h
VRAMCNT_F - VRAM-F (16K) Bank Control (W)
Ram/IRQ 4000246h
VRAMCNT_G - VRAM-G (16K) Bank Control (W)
Ram/IRQ 4000247h
WRAMCNT
Ram/IRQ 4000248h
VRAMCNT_H - VRAM-H (32K) Bank Control (W)
Ram/IRQ 4000249h
VRAMCNT_I - VRAM-I (16K) Bank Control (W)
Maths 4000280h
DIVCNT - Division Control (R/W)
Maths 4000290h
DIV_NUMER - Division Numerator (R/W)
Maths 4000298h
DIV_DENOM - Division Denominator (R/W)
Maths 40002A0h
DIV_RESULT - Division Quotient (=Numer/Denom) (R)
Maths 40002A8h
DIVREM_RESULT - Division Remainder (=Numer MOD Denom) (R)
Maths 40002B0h
SQRTCNT - Square Root Control (R/W)
Maths 40002B4h
SQRT_RESULT - Square Root Result (R)
Maths 40002B8h
SQRT_PARAM - Square Root Parameter Input (R/W)
Maths 4000300h
POSTFLG - Undoc
Maths 4000304h
POWCNT1 - Graphics Power Control Register (R/W)
Disp3D 4000320h..6A3h

2D Engine B 4001000h DISPCNT LCD Control (RW)
2D Engine B 4001008h
(same registers as GBA, some changed bits)
2D Engine B 4001008h BG0CNT BG0 Control
2D Engine B 400100Ah BG1CNT BG1 Control
2D Engine B 400100Ch BG2CNT BG2 Control
2D Engine B 400100Eh BG3CNT BG3 Control
2D Engine B 4001010h BG0HOFS BG0 X-Offset
2D Engine B 4001012h BG0VOFS BG0 Y-Offset
2D Engine B 4001014h BG1HOFS BG1 X-Offset
2D Engine B 4001016h BG1VOFS BG1 Y-Offset
2D Engine B 4001018h BG2HOFS BG2 X-Offset
2D Engine B 400101Ah BG2VOFS BG2 Y-Offset
2D Engine B 400101Ch BG3HOFS BG3 X-Offset
2D Engine B 400101Eh BG3VOFS BG3 Y-Offset
2D Engine B 4001020h BG2PA BG2 Rotation/Scaling Parameter A (dx)
2D Engine B 4001022h BG2PB BG2 Rotation/Scaling Parameter B (dmx)
2D Engine B 4001024h BG2PC BG2 Rotation/Scaling Parameter C (dy)
2D Engine B 4001026h BG2PD BG2 Rotation/Scaling Parameter D (dmy)
2D Engine B 4001028h BG2X BG2 Reference Point X-Coordinate
2D Engine B 400102Ch BG2Y BG2 Reference Point Y-Coordinate
2D Engine B 4001030h BG3PA BG3 Rotation/Scaling Parameter A (dx)
2D Engine B 4001032h BG3PB BG3 Rotation/Scaling Parameter B (dmx)
2D Engine B 4001034h BG3PC BG3 Rotation/Scaling Parameter C (dy)
2D Engine B 4001036h BG3PD BG3 Rotation/Scaling Parameter D (dmy)
2D Engine B 4001038h BG3X BG3 Reference Point X-Coordinate
2D Engine B 400103Ch BG3Y BG3 Reference Point Y-Coordinate
2D Engine B 4001040h WIN0H Window 0 Horizontal Dimensions
2D Engine B 4001042h WIN1H Window 1 Horizontal Dimensions
2D Engine B 4001044h WIN0V Window 0 Vertical Dimensions
2D Engine B 4001046h WIN1V Window 1 Vertical Dimensions
2D Engine B 4001048h WININ Inside of Window 0 and 1
2D Engine B 400104Ah WINOUT Inside of OBJ Window & Outside of Windows
2D Engine B 400104Ch MOSAIC Mosaic Size
2D Engine B 400104Eh - Not used
2D Engine B 4001050h BLDCNT Color Special Effects Selection
2D Engine B 4001052h BLDALPHA Alpha Blending Coefficients
2D Engine B 4001054h BLDY Brightness (Fade-In/Out) Coefficient
2D Engine B 4001056h - Not used
2D Engine B 400106Ch MASTER_BRIGHT 16bit - Brightness Up/Down
DSI 40021Axh
DSi Registers
DSI 4004xxxh
DSi Registers
IPC/Rom 4100000h
IPCFIFORECV - IPC Receive Fifo (R)
IPC/Rom 4100010h
Gamecard bus 4-byte data in, for manual or dma read
Debug 4FFF0xxh
Ensata Emulator Debug Registers
Debug 4FFFAxxh
No$gba Emulator Debug Registers
Exception 27FFD9Ch
NDS9 Debug Stacktop / Debug Vector (0=None)
Exception DTCM+3FF8h 4

Exception DTCM+3FFCh 4

RamCtrl 27FFFFEh
Main Memory Control

NDS Header

Offset  
Bytes  
Purpose Notes Sample
000h 12 Game Title (Uppercase ASCII, padded with 00h) .ascii "LEARNASM.NET"
00Ch 4 Gamecode (Uppercase ASCII, NTR-<code>)(0=homebrew) .ascii "0000"
010h 2 Makercode (Uppercase ASCII, eg. "01"=Nintendo) (0=homebrew) .ascii "00"
012h 1 Unitcode (00h=NDS, 02h=NDS+DSi, 03h=DSi) (bit1=DSi) .byte 0x00
013h 1 Encryption Seed Select (00..07h, usually 00h) .byte 0x00
014h 1 Devicecapacity (Chipsize = 128KB SHL nn) (eg. 7 = 16MB) .byte 0x00
015h 7 Reserved (zero filled) .space 7
01Ch 1 Reserved (zero)(except, used on DSi) .byte 0
01Dh 1 NDS Region (00h=Normal, 80h=China, 40h=Korea) (other on DSi) .byte 0
01Eh 1 ROM Version (usually 00h) .byte 0
01Fh 1 Autostart (Bit2: Skip "Press Button" after Health and Safety) .byte 4
020h 4 ARM9 rom_offset (4000h and up, align 1000h) .long Arm9_Start-HeaderStart
024h 4 ARM9 entry_address (2000000h..23BFE00h) .long 0x02000000
028h 4 ARM9 ram_address (2000000h..23BFE00h) .long 0x02000000
02Ch 4 ARM9 size (max 3BFE00h) (3839.5KB) .long Arm9_End-Arm9_Start
030h 4 ARM7 rom_offset (8000h and up) .long Arm7_Start-HeaderStart
034h 4 ARM7 entry_address (2000000h..23BFE00h, or 37F8000h..3807E00h) .long 0x03800000
038h 4 ARM7 ram_address (2000000h..23BFE00h, or 37F8000h..3807E00h) .long 0x03800000
03Ch 4 ARM7 size (max 3BFE00h, or FE00h) (3839.5KB, 63.5KB) .long Arm7_End-Arm7_Start
040h 4 File Name Table (FNT) offset
.long 0
044h 4 File Name Table (FNT) size
.long 0
048h 4 File Allocation Table (FAT) offset
.long 0
04Ch 4 File Allocation Table (FAT) size
.long 0
050h 4 File ARM9 overlay_offset
.long 0
054h 4 File ARM9 overlay_size
.long 0
058h 4 File ARM7 overlay_offset
.long 0
05Ch 4 File ARM7 overlay_size
.long 0
060h 4 Port 40001A4h setting for normal cmd (usually 00586000h) .long 0x00586000
064h 4 Port 40001A4h setting for KEY1 cmd (usually 001808F8h) .long 0x001808F8
068h 4 Icon/Title offset (0=None) (8000h and up) .long 0
06Ch 2 Secure Area Checksum CRC-16 of [[020h]..00007FFFh] .word 0
06Eh 2 Secure Area Delay (in 131kHz units) (051Eh=10ms or 0D7Eh=26ms) .word 0
070h 4 ARM9 Auto Load List Hook RAM Addr. \endaddr of auto-load .long 0
074h 4 ARM7 Auto Load List Hook RAM Addr. /functions .long 0
078h 8 Secure Area Disable (by encrypted "NmMdOnly") (usually zero) .space 8
080h 4 Total Used ROM size (remaining/unused bytes usually FFh-padded) .long 0
084h 4 ROM Header Size (4000h) .long 0x4000
088h 28h Reserved (zero filled except, [88h..93h] used on DSi) .space 0x28
0B0h 10h Reserved (zero filled or "DoNotZeroFillMem"=unlaunch fastboot) .space 0x10
0C0h 9Ch Nintendo Logo (compressed bitmap, same as in GBA Headers) .space 0x9C
15Ch 2 Nintendo Logo Checksum CRC-16 of [0C0h-15Bh], fixed CF56h .word 0
15Eh 2 Header Checksum CRC-16 of [000h-15Dh] .word 0
160h 4 Debug rom_offset (0=none) (8000h and up) only if debug .long 0
164h 4 Debug size (0=none) (max 3BFE00h) .long 0
168h 4 Debug ram_address (0=none) (2400000h..27BFE00h) SIO and 8MB .long 0
16Ch 4 Reserved (zero filled) (transferred, and stored, but not used) .long 0
170h 90h Reserved (zero filled) (transferred, and stored, but not used) .space 0x90

Bare Metal ARM Assembly Hello World Example
There is a working 'single asm' bare metal sample in the sources.7z

the JOY of NDS
The Nintendo DS joypad buttons are split into two addresses...

The first is the classic GBA keys - these can be read from either the ARM9 or ARM7
0x4000130 - Joypad Keys (GBA Type)    ------LRDULRSsBA

The second is the new NDS keys... these can ONLY be read from the ARM7
0x4000136 - Extra Key Input    --------HP--D-YX

a PEN in the BUS
Accessing the PEN pos can only be done from the ARM7 - and its not entirely easy!
the X and Y pos use 12 bits each, but we can only load them 8 bits at a time, via a serial bus....

0x40001C0 - SPICNT - SPI Bus Control/Status Register
0x40001C2 - SPIDATA - SPI Bus Data/Strobe Register

Here is the sequence for reading an axis...

#0b1000101000000001 -> SPICNT  (Select Touchscreen)
#0b11010100 -> SPIDATA (Xpos) ... OR .... #0b10010100 -> SPIDATA (Ypos)
SPICNT -> Wait for Bit 7 of SPICNT to become 0
#0 -> SPIDATA
SPICNT -> Wait for Bit 7 of SPICNT to become 0
SPIDATA-> top 8 bits of axis HHHHHHHH
#0b1000001000000001 ->SPICNT (Get 2nd byte)
#0 -> SPIDATA
SPICNT -> Wait for Bit 7 of SPICNT to become 0
SPIDATA-> bottom 4 bits of axis LLLL0000

Sound Registers (ARM7)
Address Bytes Name Description Bits Notes
4000304h 2 POWCNT2 Sound/Wifi Power Control Register (R/W) ------WS S=Sound on W=Wifi on
40004x0h 4 SOUNDxCNT Sound Channel X Control Register (R/W) SFFRRWWW-PPPPPPPH-----DD-VVVVVVV S=Start F=Format R=Repeat W=Wave duty P=Panning H=Hold D=volume Div V=Volume
40004x4h 4 SOUNDxSAD Sound Channel X Data Source Register (W) -----AAAAAAAAAAAAAAAAAAAAAAAA00 A=Address of sample
40004x8h 2 SOUNDxTMR Sound Channel X Timer Register (W) FFFFFFFFFFFFFFFF F=Frequency
40004xAh 2 SOUNDxPNT Sound Channel X Loopstart Register (W) LLLLLLLLLLLLLLLL L=Loop Start
40004xCh 4 SOUNDxLEN Sound Channel X Length Register (W) LLLLLLLLLLLLLLLL L=Length
4000500h 2 SOUNDCNT Sound Control Register (R/W) M-31RRLL-VVVVVVV M=Master on 31=output 31 to mixer RRLL=output from V=master Volume
4000504h 2 SOUNDBIAS Sound Bias Register (R/W) -------BBBBBBBBBB B=Sound Bias
4000508h 1 SNDCAP0CNT Sound Capture 0 Control Register (R/W) S---FEsC S=Start F=Format R=Repeat s=source C=Control
4000509h 1 SNDCAP1CNT Sound Capture 1 Control Register (R/W) S---FEsC
4000510h 4 SNDCAP0DAD Sound Capture 0 Destination Address (R/W) -----AAAAAAAAAAAAAAAAAAAAAAAA00 A=Address of Capture
4000514h 2 SNDCAP0LEN Sound Capture 0 Length (W) LLLLLLLLLLLLLLLL L=Length
4000518h 4 SNDCAP1DAD Sound Capture 1 Destination Address (R/W) -----AAAAAAAAAAAAAAAAAAAAAAAA00
400051Ch 2 SNDCAP1LEN Sound Capture 1 Length (W) LLLLLLLLLLLLLLLL L=Length