DS Video Information
Two backlit LCD screens made by Sharp. 256x192 resolution
NDS video timing information:
- Both screens are updated simultaneously.
- 355 pixels/line
- 263 lines/frame
- 2130 clocks/line
- 6 clocks/pixel
- H-blank signal is low for 264 pixels every scanline
- V-blank signal is low for 193 scanlines + 8 pixels every frame
- 560,190 clocks/frame
- 59.8 frames/second
- 15,727.4 lines/second
- Note: this timing is identical to NTSC television.
- The clock cycles at 33,499,362.6 Hz (timer input)
Note: these timings are based on a single program (with multiple overlapping methods of measuring some quantities), and on a single DS. Another DS may have a slightly different clock rate.
Although there are 256x192 visible pixels, the v-blank bit stays low for 193 scanlines and 8 pixels longer than that, and the h-blank bit stays low for 8 pixels longer than it should.
<Theory>
</Theory>
<< | Video | >>
There are two nearly identical 2D cores in the Nintendo DS. The main core has an additional background mode.
NOTE: SOME OF THIS INFORMATION IS WRONG, BEWARE
Core-specific registers
Core | Register offset |
A | 0x04000000 |
B | 0x04001000 |
Offset:Width | Mode | Name |
0x00:32 | R/W | DISPLAY_CR |
0x08:16 | R/W | BG0_CR |
0x0A:16 | R/W | BG1_CR |
0x0C:16 | R/W | BG2_CR |
0x0E:16 | R/W | BG3_CR |
0x10:16 | W | BG0_X |
0x12:16 | W | BG0_Y |
0x14:16 | W | BG1_X |
0x16:16 | W | BG1_Y |
0x18:16 | W | BG2_X |
0x1A:16 | W | BG2_Y |
0x1C:16 | W | BG3_X |
0x1E:16 | W | BG3_Y |
0x20:16 | W | BG2_HDX |
0x22:16 | W | BG2_HDY |
0x24:16 | W | BG2_VDX |
0x26:16 | W | BG2_VDY |
0x28:32 | W | BG2_X0 |
0x2C:32 | W | BG2_Y0 |
0x30:16 | W | BG3_HDX |
0x32:16 | W | BG3_HDY |
0x34:16 | W | BG3_VDX |
0x36:16 | W | BG3_VDY |
0x38:32 | W | BG3_X0 |
0x3C:32 | W | BG3_Y0 |
0x40:16 | W | WIN0_X |
0x42:16 | W | WIN1_X |
0x44:16 | W | WIN0_Y |
0x46:16 | W | WIN1_Y |
0x48:16 | R/W | WIN_IN (3f3f) |
0x4A:16 | R/W | WIN_OUT (3f3f) |
0x4C:16 | W | MOSAIC |
0x50:16 | R/W | BLEND_CR (3fff) |
0x52:16 | R/W | BLEND_AB (1f1f) |
0x54:16 | W | BLEND_Y |
0x6C:16 | R/W | BRIGHT_CR (c01f) |
DISPLAY_CONTROL
bit | name |
31 | Extended sprite palette enable |
30 | Extended background palette enable |
29..24 | ? |
23 | ? |
22..20 | Extended sprite mode |
19..18 | Framebuffer select (extended mode 2) |
17..16 | Extended mode |
15 | Sprite window enable |
14 | Window 1 enable |
13 | Window 0 enable |
12 | Sprite enable |
11 | BG3 enable |
10 | BG2 enable |
9 | BG1 enable |
8 | BG0 enable |
7 | Forced blank |
6..4 | Sprite mode |
3 | 0: BG0 is 2D layer, 1: BG0 is 3D layer |
2..0 | Display mode |
Extended Mode:
- 0: Framebuffer
- 1: GBA-style (see display mode)
- 2: acts like framebuffer
- 3: ?
DISP_CR2
bit | name |
31 | Extended sprite palette enable |
30 | Extended background palette enable |
29..23 | ? |
22..20 | Extended sprite mode |
19..18 | ? |
17..16 | Extended mode |
15 | Sprite window enable |
14 | Window 1 enable |
13 | Window 0 enable |
12 | Sprite enable |
11 | BG3 enable |
10 | BG2 enable |
9 | BG1 enable |
8 | BG0 enable |
7 | Forced blank |
6..4 | Sprite mode |
3 | ? |
2..0 | Display mode |
Extended Mode:
- 0: ?
- 1: GBA-style (see display mode)
- 2: ?
- 3: ?
NOTE: THIS INFORMATION IS POSSIBLY WRONG Display Mode (ignored unless Extended Mode is 1):
- 0: Mode 0 (4 text layers)
- 1: Mode 1 (2 text layers, 1 rot/scale)
- 2: Mode 2 (2 rot/scale)
- 3: Mode 3 (15 bpp framebuffer, single page)
- 4: Mode 4 (8 bpp indexed framebuffer, double buffered)
- 5: Mode 5 (bg0 is text/3d, bg1 is text, bg2 is extended rot/scale background)
- 6: Mode 6 ?
Extended rot/scale background in mode 5: Size fields: BG_BMP16_128x128 BG_BMP16_256x256 BG_BMP16_512x256 BG_BMP16_512x512
Each element in the background is a 16 bit direct-color entry A1B5G5R5. If the top bit is zero, the pixel is transparent, otherwise it is opaque.
Differences to the GBA:
- Alpha bit (modes 3 and 5 were always opaque on GBA)
- Multiple sizes
- Rot/scale registers are *not* set to straight display by default
BRIGHT_CR
bit | name |
15..14 | Mode |
13..5 | - |
4..0 | Amount |
Mode:
- 00, 11: Amount ignored, middle brightness
- 01: Increase, brightness = middle + amount (0x8 and above are pretty much useless)
- 10: Decrease, brightness = middle - amount (0x8 and above are pretty much useless)
Bits marked as - read as 0, and ignore writes.
3D Core Registers
Name | Width | Address |
GFX_CONTROL | 16 | 0x04000060 |
GFX_FIFO | 32 | 0x04000400 |
GFX_STATUS | 32 | 0x04000600 |
GFX_TEX_FORMAT | 32 | 0x040004A8 |
GFX_CLEAR_COLOR | 32 | 0x04000350 |
GFX_CLEAR_DEPTH | 16 | 0x04000354 |
GFX_LIGHT_VECTOR | 32 | 0x040004C8 |
GFX_LIGHT_COLOR | 32 | 0x040004CC |
GFX_DIFFUSE_AMBIENT | 32 | 0x040004C0 |
GFX_SPECULAR_EMISSION | 32 | 0x040004C4 |
GFX_SHININESS | 32 | 0x040004D0 |
GFX_POLY_FORMAT | 32 | 0x040004A4 |
GFX_ALPHA_TEST | 16 | 0x04000340 |
GFX_FLUSH | 32 | 0x04000540 |
GFX_VIEWPORT | 32 | 0x04000580 |
GFX_TOON_TABLE | 16 | 0x04000380 |
GFX_EDGE_TABLE | 16 | 0x04000330 |
GFX_VERTEX_RAM_USAGE | 16 | 0x04000606 |
GFX_POLYGON_RAM_USAGE | 16 | 0x04000604 |
GFX_TEX_FORMAT
31..30 | Texgen mode |
29 | ? |
28..26 | Texture Format |
25..23 | Texture Height |
22..20 | Texture Width |
19 | Flip T |
18 | Flip S |
17 | Wrap T |
16 | Wrap S |
15..0 | Texture address / 8 |
Texgen mode affects what texture coordinates are passed into the rasterizer.
00 | Tex-coord passed through |
01 | Tex-coord * texture matrix |
10 | Normal * texture matrix |
11 | Vertex * texture matrix |
Texture formats:
0 | ? |
1 | RGB32_A3 - 32 color palette, 3 bits of alpha |
2 | RGB4 - 4 color palette (2 bpp) |
3 | RGB16 - 16 color palette (4 bpp) |
4 | RGB256 - 256 color palette (8 bpp) |
5 | Compressed |
6 | RGB8_A5 - 8 color palette, 5 bits of alpha |
7 | RGBA - 15 bpp RGB plus 1 bit alpha in MSB (16 bpp) |
Texture sizes are powers of 2 from 8 to 1024 (0..7). A texture does not have to be square.
libnds function calls associated with this register:
- glBindTexture
- glTexImage2d
GFX_POLY_FORMAT
31..30 | ? |
29..24 | Polygon ID |
23..21 | ? |
20..16 | Polygon alpha (31: opaque) |
15..8 | ? |
7..6 | Cull mode (00: front and back, 01: front, 10: back, 11: none) |
5..4 | Mode (00: Modulate, 01: Decal, 10: Toon shading, 11: Shadow) |
3 | Light 3 enable |
2 | Light 2 enable |
1 | Light 1 enable |
0 | Light 0 enable |
libnds function calls associated with this register:
- glPolyFmt
GFX_LIGHT_VECTOR
31..30 | Light ID # |
29..20 | z component of normal (.10 fixed) |
19..10 | y component of normal (.10 fixed) |
9..0 | x component of normal (.10 fixed) |
libnds function calls associated with this register:
- glLight
GFX_LIGHT_COLOR
31..30 | Light ID # |
14..10 | RGB color |
libnds function calls associated with this register:
- glLight
GFX_DIFFUSE_AMBIENT
31..16 | Ambient color |
15..0 | Diffuse color |
GFX_SPECULAR_EMISSION
31..16 | Emission color |
15..0 | Specular color |
libnds function calls associated with this register:
- glMaterialf
GFX_CONTROL
15..14 | ? |
13 | Polygon / vertex memory overflow (write 1 to reset) |
12 | Line buffer overflow (write 1 to reset) |
11..6 | ? |
5 | Outlining (1: enabled) |
4 | Antialiasing (1: enabled) |
3 | Alpha blending (1: enabled) |
2 | Alpha test (1: enabled) |
1 | Shading mode (0: toon, 1: highlighting) |
0 | Texture-mapping (1: enabled) |
GFX_ALPHA_TEST
15..5 | - |
4..0 | Alpha threshold |
If enabled (see GFX_CONTROL or glEnable), fragments are discarded if their post-blend alpha value is below the threshold set in this register.
libnds function calls associated with this register:
- glAlphaFunc
Geometry Engine
Name | Width | Address | Description |
NOP | 32 | 0x04000400 | No-operation |
MATRIX_CONTROL | 32 | 0x04000440 | Matrix control register |
MATRIX_PUSH | 32 | 0x04000444 | Matrix push |
MATRIX_POP | 32 | 0x04000448 | Matrix pop |
MATRIX_STORE | 32 | 0x0400044C | Matrix store |
MATRIX_RESTORE | 32 | 0x04000450 | Matrix restore |
MATRIX_IDENTITY | 32 | 0x04000454 | Load identity matrix |
MATRIX_LOAD4x4 | 32 | 0x04000458 | Load 4x4 matrix write port |
MATRIX_LOAD4x3 | 32 | 0x0400045C | Load 4x3 matrix write port |
MATRIX_MULT4x4 | 32 | 0x04000460 | Multiply 4x4 matrix write port |
MATRIX_MULT4x3 | 32 | 0x04000464 | Multiply 4x3 matrix write port |
MATRIX_MULT3x3 | 32 | 0x04000468 | Multiply 3x3 matrix write port |
MATRIX_SCALE | 32 | 0x0400046C | Scale matrix write port |
MATRIX_TRANSLATE | 32 | 0x04000470 | Translate matrix write port |
MATRIX_READ_PROJECTION | 32 | 0x04000640 | Read port for projection matrix |
MATRIX_READ_ROTATION | 32 | 0x04000680 | Read port for ?rotation? matrix |
POINT_RESULT | 32 | 0x04000620 | . |
VECTOR_RESULT | 16 | 0x04000630 | . |
GFX_COLOR | 32 | 0x04000480 | Set color |
GFX_NORMAL | 32 | 0x04000484 | Set normal |
GFX_TEX_COORD | 32 | 0x04000488 | Set texture coordinate |
GFX_VERTEX16 | 32 | 0x0400048C | Vertex write port |
GFX_VERTEX10 | 32 | 0x04000490 | Vertex write port |
GFX_VERTEX_XY | 32 | 0x04000494 | Vertex write port |
GFX_VERTEX_XZ | 32 | 0x04000498 | Vertex write port |
GFX_VERTEX_YZ | 32 | 0x0400049C | Vertex write port |
GFX_VERTEX_DIFF | 32 | 0x040004A0 | Vertex write port |
GFX_BEGIN | 32 | 0x04000500 | Begin a primitive |
GFX_END | 32 | 0x04000504 | End a primitive |
GFX_BOX_TEST | 32 | 0x040005C0 | . |
GFX_BEGIN
Starts the processing of primitives.
31..2 | ? |
1..0 | Type (00: Triangles, 01: Quads, 10: Triangle Strip, 11: Quad Strip) |
GFX_END
Stops the processing of primitives / finalizes them.
Just like OpenGL, you should only issue vertex commands in between a begin / end pair.
libnds function calls associated with these registers:
- glBegin
- glEnd
MATRIX_TRANSLATE
Three writes multiples the current matrix with a translate matrix of the form:
1.0 | 0.0 | 0.0 | write1 |
0.0 | 1.0 | 0.0 | write2 |
0.0 | 0.0 | 1.0 | write3 |
0.0 | 0.0 | 0.0 | 1.0 |
libnds function calls associated with these registers:
- glTranslatev
- glTranslate3f32
- glTranslatef32
- glTranslatef
MATRIX_SCALE
Three writes multiples the current matrix with a scale matrix of the form:
write1 | 0.0 | 0.0 | 0.0 |
0.0 | write2 | 0.0 | 0.0 |
0.0 | 0.0 | write3 | 0.0 |
0.0 | 0.0 | 0.0 | 1.0 |
libnds function calls associated with these registers:
- glScalev
- glScalef32
- glScalef
MATRIX_MULT3x3
After 9 writes, the current matrix is multipled by a 3x3 matrix formed from the writes.
MATRIX_MULT4x3
After 12 writes, the current matrix is multipled by a 4x3 matrix formed from the writes.
MATRIX_MULT4x4
After 16 writes, the current matrix is multipled by a 3x3 matrix formed from the writes.
libnds function calls associated with these registers:
- glMultMatrix3x3
- glMultMatrix4x3
- glMultMatrix4x4
MATRIX_LOAD4x4
Write port to the 4x4 matrix hardware (f32 format).
MATRIX_LOAD4x3
Write port to the 4x4 matrix hardware (f32 format). After 12 writes, the last 4 elements of the matrix are set to 0.0 0.0 0.0 1.0.
libnds function calls associated with these registers:
- glLoadMatrix4x3
- glLoadMatrix4x4
- Various other routines use them behind the scenes.
libnds fixed point / floating point / integer conversion routines:
- intof32 (integer -> f32)
- floatof32 (float -> f32)
- inttot16 (integer -> t16)
- floattot16 (float -> t16)
- inttov16 (integer -> v16)
- floattov16 (float -> v16)
- inttov10 (integer -> v10)
- floattov10 (float -> v10)
Sprites
OAM Entry Attribute 0,1 | |
7..0 | Y |
9..8 | Rot/scale (00: Normal, 01: Rot/scale, 10: Disabled, 11: Double-size rot/scale) |
11..10 | Mode (00: Normal, 01: Transparent, 10: Object window, 11: Bitmap?) |
12 | Mosaic (1: Enabled) |
13 | Color depth (0: 16, 1: 256) |
15..14 | Shape (00: Square, 01: Wide, 10: Tall, 11: Illegal) |
24..16 | X |
29..25 | Rot/scale matrix index |
28 | HF |
29 | VF |
31..30 | Size |
OAM Entry Attribute 2 | |
9..0 | Tile index |
11..10 | Priority |
15..12 | Palette index |
Attribute 3 is actually a part of the rotation/scale parameters for sprites.
Each core commands 128 sprites, taking up 768 bytes, the other 256 bytes (interspersed between sprites) form 32 rot/scale matricies.
OAM locations:
- 0x07000000 for 2D Core A
- 0x07000400 for 2D Core B
Palettes in a nutshell
- There are 4 palettes, two per display.
- Sprites get one palette, and background layers another.
- Each palette has 256 halfword entries.
- Each entry contains 5 bits of red, 5 bits of green, 5 bits of blue, and an unused bit.
- PALETTE_BG1 is at 0x05000000 (background palette for 2D core A)
- PALETTE_FG1 is at 0x05000200 (sprite palette for 2D core A)
- PALETTE_BG2 is at 0x05000400 (background palette for 2D core B)
- PALETTE_FG2 is at 0x05000600 (sprite palette for 2D core B)
Color structure
15 | 14..10 | 9..5 | 4..0 |
pad | blue | green | red |
Video Modes
Video Modes
Name | Value to write to CR |
Mode 0 | 0x00010000 |
Mode 1 | 0x00010001 |
Mode 2 | 0x00010002 |
Mode 3 | 0x00010003 |
Mode 4 | 0x00010004 |
Mode 5 | 0x00010005 |
Mode 6 | 0x00010006 |
Framebuffer | 0x00020000 |
VRAM Banks
Name | Define | Register | Size | Location |
Core A | ? | ? | 256 KB | 0x06000000 |
Core B | ? | ? | 256 KB | 0x06040000 |
Bank A | VRAM_A_CR | 0x04000240:8 | 128 KB | 0x06800000 |
Bank B | VRAM_B_CR | 0x04000241:8 | 128 KB | 0x06820000 |
Bank C | VRAM_C_CR | 0x04000242:8 | 128 KB | 0x06840000 |
Bank D | VRAM_D_CR | 0x04000243:8 | 128 KB | 0x06860000 |
Bank E | VRAM_E_CR | 0x04000244:8 | 64 KB | 0x06880000 |
Bank F | VRAM_F_CR | 0x04000245:8 | 16 KB | 0x06890000 |
Bank G | VRAM_G_CR | 0x04000246:8 | 16 KB | 0x06894000 |
Bank H | VRAM_H_CR | 0x04000248:8 | 32 KB | 0x06898000 |
Bank I | VRAM_I_CR | 0x04000249:8 | 16 KB | 0x068A0000 |
VRAM_A_CR (128 KB)
7 | 1: Enabled |
4..3 | Offset |
1..0 | Mode |
Modes:
Bits | Name | ARM9 address, offset effect |
00 | Framebuffer | 0x06800000, offset ignored? |
01 | Main BG | 0x06000000, 0x06020000, 0x06040000, 0x06060000 |
10 | Main sprites | 0x06400000 if offset=0x, 0x06420000 if offset=1x |
11 | Textures | bank 0..3, * |
VRAM_B_CR (128 KB)
7 | 1: Enabled |
4..3 | Offset |
1..0 | Mode |
Modes:
Bits | Name | ARM9 address, offset effect |
00 | Framebuffer | 0x06820000, offset ignored? |
01 | Main BG | 0x06000000, 0x06020000, 0x06040000, 0x06060000 |
10 | Main sprites | 0x06400000 if offset=0x, 0x06420000 if offset=1x |
11 | Textures | bank 0..3, * |
VRAM_C_CR (128 KB)
7 | 1: Enabled |
4..3 | Offset |
2..0 | Mode |
Modes:
Bits | Name | ARM9 address, offset effect |
000 | Framebuffer | 0x06840000, offset ignored? |
001 | Main BG | 0x06000000, 0x06020000, 0x06040000, 0x06060000 |
010 | ARM7 | *, arm7: 0x06000000 if offset=0x, 0x06020000 if offset=1x |
011 | Textures | bank 0..3, * |
100 | Sub BG | 0x06200000, offset ignored? |
101 | ? | ? |
110 | ? | ? |
111 | ? | ? |
VRAM_D_CR (128 KB)
7 | 1: Enabled |
4..3 | Offset |
2..0 | Mode |
Modes:
Bits | Name | ARM9 address, offset effect |
000 | Framebuffer | 0x06860000, offset ignored? |
001 | Main BG | 0x06000000, 0x06020000, 0x06040000, 0x06060000 |
010 | ARM7 | *, arm7: 0x06000000 if offset=0x, 0x06020000 if offset=1x |
011 | Textures | bank 0..3, * |
100 | Sub BG | 0x06600000, offset ignored? |
101 | ? | ? |
110 | ? | ? |
111 | ? | ? |
retains 0x87
VRAM_E_CR (64 KB)
7 | 1: Enabled |
2..0 | Mode |
Modes:
Bits | Name | ARM9 address |
000 | Framebuffer | 0x06880000 |
001 | Main BG | 0x06000000 |
010 | Main sprites | 0x06400000 |
011 | Textures palettes 0..3 | * |
100 | Extended main BG palettes 0..3 | |
101 | ? | ? |
110 | ? | ? |
111 | ? | ? |
VRAM_F_CR (16 KB)
7 | 1: Enabled |
4..3 | Offset |
2..0 | Mode |
Modes:
Bits | Name | ARM9 address, offset effect |
000 | Video core | 0x06890000, offset ignored? |
001 | Main BG | 0x06000000, 0x06004000, 0x06100000, 0x06140000 |
010 | Main sprites | 0x06400000, 0x06404000, 0x06410000, 0x06414000 |
011 | Texture palette | *, palette 0,1,4,5 |
100 | Extended BG palettes | *, 0..1, 2..3, ?, ? |
101 | Extended sprite palettes | *, offset ignored |
110 | ? | ? |
111 | ? | ? |
VRAM_G_CR (16 KB)
7 | 1: Enabled |
4..3 | Offset |
2..0 | Mode |
Bits | Name | ARM9 address, offset effect |
000 | Video core | 0x06894000, offset ignored? |
001 | Main BG | 0x06000000, 0x06004000, 0x06100000, 0x06140000 |
010 | Main sprites | 0x06400000, 0x06404000, 0x06410000, 0x06414000 |
011 | Texture palette | *, palette 0,1,4,5 |
100 | Extended BG palettes | *, 0..1, 2..3, ?, ? |
101 | Extended sprite palettes | *, offset ignored |
110 | ? | ? |
111 | ? | ? |
--- 0x248: retains 8383
VRAM_H_CR (32 KB)
7 | 1: Enabled |
1..0 | Mode |
Bits | Name | ARM9 address |
00 | Video core | 0x06898000 |
01 | Sub BG | 0x06200000 |
10 | Extended sub sprite palettes 0..3 | * |
11 | ? | ? |
VRAM_I_CR (16 KB)
7 | 1: Enabled |
1..0 | Mode |
Bits | Name | ARM9 address |
00 | Video core | 0x068A0000 |
01 | Sub BG | 0x06208000 |
10 | Sub sprites | 0x06600000 |
11 | Extended sub BG palettes 0..3 | * |
* Not mapped in ARM9 CPU address space.
The 2D cores can use extended palettes, which are an additional 16 palettes of 256 colors each (8 KB per set). There is one set for each background (BG0..BG3).
For the main core, you can use bank E (all 4 sets loaded) or banks F or G (sets 0,1 and/or sets 2,3) to store the extended palettes.
For the sub core, you can only use bank H (all 4 sets loaded).
You need to set the VRAM bank owner bits correctly, and enable extended palettes in the DISPLAY_CONTROL register.
ARM9:
0x240: retains 9b9b 0x242: retains 9f9f 0x244: retains 9f87 0x246: retains 039f 0x248: retains 8383
On the ARM7: reads 0300
Thanks to Mic for some information on this page.