−Table of Contents
LCD controller
The gamepad provides simple framebuffer-based display hardware.
Register map:
Address | Desc. |
---|---|
0xF0009400 | Horizontal timing control |
0xF0009404 | Vertical timing control |
0xF0009408 | ?? |
0xF000940C | ?? |
0xF0009410 | Horizontal start of display |
0xF0009414 | Vertical start of display |
0xF0009418 | Horizontal end of display |
0xF000941C | Vertical end of display |
0xF0009420 | ?? video-out X offset? |
0xF0009424 | ?? video-out width? |
0xF0009428 | ?? video-out Y offset? |
0xF000942C | ?? video-out height? |
0xF0009430 | ?? |
0xF0009434 | ?? |
0xF0009460 | Framebuffer X offset |
0xF0009464 | Framebuffer width |
0xF0009468 | Framebuffer Y offset |
0xF000946C | Framebuffer height |
0xF0009470 | Framebuffer stride |
0xF0009474 | Framebuffer address |
0xF0009478 | ?? |
0xF0009480 | Display control |
0xF0009484 | ?? |
0xF0009488 | ?? |
0xF0009490 | ?? |
0xF0009494 | ?? |
0xF00094B0 | Pixel format |
0xF00094B4 | ?? |
0xF00094B8 | ?? |
0xF00094BC | ?? |
0xF00094C0 | ?? |
0xF00094C4 | ?? |
0xF00094C8 | VCount - current vertical position |
0xF00094D0+(N*4) | YUV→RGB matrix (N=0..8) |
0xF00094F4 | ?? |
0xF00094F8 | Camera sync |
0xF00094FC | Counter of sorts |
0xF0009500 | Palette address |
0xF0009504 | Palette data |
0xF0009508 | VCount IRQ position 1 |
0xF000950C | VCount IRQ position 2 |
0xF0009510 | VCount IRQ position 3 |
0xF0009514 | VCount IRQ position 4 |
0xF0009600+(N*4) | Color correction LUT entry N (N=0..31) |
0xF0009684 | Color correction mask |
0xF0009700 | ?? |
0xF0009704 | ?? |
0xF0009708 | ?? |
Related IRQs:
IRQ | Desc. |
---|---|
0x12 | ?? |
0x15 | Display start (VBlank end) |
0x16 | VBlank |
0x1E | VCount match |
The LCD pixel clock is, by default, 32 MHz. It is sourced from register 0xF0000034.
Framebuffer registers
0xF0009400
Controls horizontal timing.
Bits | Desc. |
---|---|
0-11 | Total number of horizontal pixels |
16-27 | ??? |
The number of horizontal pixels defines how long each line lasts. Should be set to 1047 for 60FPS output.
Bits 16-27 affect video timings in weird, subtle ways.
0xF0009404
Controls vertical timing.
Bits | Desc. |
---|---|
0-10 | Total number of vertical lines |
16-24 | ??? |
The number of vertical lines defines how long each frame lasts. Should be set to 510 for 60FPS output.
Bits 16-24 cause VBlank to last a little longer when set to a value lower than 0x100.
0xF0009410
Horizontal start of display.
Should be set to 96 to match LCD output.
This register is 11 bits wide.
0xF0009414
Vertical start of display.
Should be set to 8 to match LCD output. TODO: this register works weirdly
This register is 13 bits wide.
0xF0009418
Horizontal end of display.
Should be set to 950 to match LCD output. Smaller values result in garbage being displayed after the end of the display area. TODO: some values behave weirdly
This register is 11 bits wide.
0xF000941C
Vertical end of display.
Should be set to 488 to match LCD output. Smaller values result in a longer VBlank interval at the cost of some vertical resolution (the last line to be displayed will be repeated across the rest of the screen).
This register is 9 bits wide.
0xF0009460
X offset, specifies where the framebuffer will start on the screen.
0xF0009464
Framebuffer width in pixels.
0xF0009468
Y offset, specifies where the framebuffer will start on the screen.
0xF000946C
Framebuffer height in pixels.
0xF0009470
Framebuffer stride. It is in bytes, except for pixel formats 2 and 3, where it is in 16-bit units.
0xF0009474
Framebuffer address. This register is 22 bits wide, thus the framebuffer may only be within main RAM.
0xF0009480
Display control register, not yet known how this works.
Bits | Desc. |
---|---|
0 | ?? breaks display |
1 | Must be set for display to work. Presumably enables overlay. |
2 | ?? causes weird effects |
3 | ?? |
4 | Must be set for display to work. Presumably general display enable. |
0xF00094B0
Pixel format register.
Bits | Desc. |
---|---|
0-1 | Pixel format |
2 | ?? |
3 | ?? |
7 | Color mode; 0=RGB, 1=YUV |
8 | ?? collapses overlay to 1px vertical line |
9 | ?? |
10 | ?? |
16-23 | ?? (set to 0xFF) |
The following pixel formats are supported:
Value | Desc. |
---|---|
0 | 8-bit paletted |
1 | 4-bit paletted (LSb first) |
2 | 16-bit ARGB1555 |
3 | 16-bit RGB565 |
For the paletted formats, see the palette registers.
Bit 7 causes color components to be interpreted as YUV, with the following mapping: R=V, G=Y, B=U. It seems the handling is different based on the pixel format? Notably, in YUV mode, pixel formats 0 and 1 seem to entirely ignore the palette and instead somehow directly convert indices to color components.
In YUV mode, the matrix at 0xF00094D0..0xF00094F0 is used to convert the YUV components to RGB.
0xF00094C8
Current vertical position.
0xF00094D0+(N*4)
YUV→RGB matrix.
Register | Description | Default value |
---|---|---|
0xF00094D0 | Y → G factor | 0x0A5 = 74 |
0xF00094D4 | U → G factor | 0x04E = -14 |
0xF00094D8 | V → G factor | 0x062 = -34 |
0xF00094DC | Y → B factor | 0x0A5 = 74 |
0xF00094E0 | U → B factor | 0x122 = 136 |
0xF00094E4 | V → B factor | 0x000 = 0 |
0xF00094E8 | Y → R factor | 0x0A5 = 74 |
0xF00094EC | U → R factor | 0x000 = 0 |
0xF00094F0 | V → R factor | 0x0B9 = 114 |
The factors work in a bit of a weird way.
Bits | Desc. |
---|---|
0-5 | Amount |
6 | Sign |
7-8 | Multiplier; 0=1, 1=2, 2/3=4 |
The sign bit makes the value negative, but it's not two's complement. Instead: 0x3F = 63, 0x7F = -63.
The multiplier allows to increase the final value. For example, values 0x30, 0x98, 0x10C and 0x18C are equivalent.
Note: YUV mode produces darker colors, even with maximum factor values. One can use the color correction registers at 0xF0009600 to compensate for this.
0xF00094F8
Camera sync.
Bits | Desc. |
---|---|
0-10 | Vertical position |
15 | ??? |
This register allows to synchronize camera output to the display. The camera frame IRQ fires 8 scanlines after the specified position.
This register can be disabled by setting it to a value equal to or greater than the display's total vertical span (as set in 0xF0009404). In this case, the camera outputs at its 'natural' framerate without synchronizing to the display, and the camera frame IRQ fires whenever a frame is finished.
0xF00094FC
Counter of sorts. Seems to be based on the count-up timer.
This register is 27 bits wide.
Palette registers
0xF0009500
Palette address. Specifies which palette entry will be accessed by 0xF0009504.
0xF0009504
Palette data.
Reading from this register returns the palette entry pointed by the address register.
Writing to this register will write to the palette entry pointed by the address register, and increment the address register.
The color format is ARGB8888. The MSB of color values seems to actually function as an alpha value, which suggests that the LCD controller may be able to blend the framebuffer with something else, presumably output from the video decoder.
VCount IRQ registers
0xF0009508 to 0xF0009514
These registers allow to trigger IRQ 0x1E based on the current vertical position (VCount).
When VCount matches any of these registers, IRQ 0x1E is triggered. The multiple registers allow to split the frame time in smaller intervals.
These registers are 11 bits wide. They can be 'disabled' by setting them to a value outside of the configured vertical range.
The stock firmware uses IRQ 0x1E to perform input polling and audio sync. The settings it uses divide each frame into 3 equal parts, effectively firing IRQ 0x1E at a 180 Hz interval.
Color correction registers
These registers allow to correct output color levels. They are presumably used to do gamma correction.
Individual RGB components are simply corrected based on a lookup table with 33 entries.
0xF0009600+(N*4)
These registers are the correction LUT.
Presumably, interpolation is used to make up for the limited precision of this LUT, ie. values 0..7 would be mapped to entries 0/1, values 8..15 would be mapped to entries 1/2, and so on.
These registers are 9 bits wide.
0xF0009684
Color correction mask. Enables color correction for individual channels.
Bits | Desc. |
---|---|
0 | Red |
1 | Blue |
2 | Green |
0 means to output the corresponding channel as-is, 1 means to correct the corresponding channel using the LUT.
Timing? registers
0xF0009704
Unknown. Affects the way video sync/data is sent to the LCD. Has no effect on video timings.
Display modes
The stock firmware has settings for three different video modes.
Setting | Mode 0 | Mode 1 | Mode 2 |
---|---|---|---|
Mode | 854×480 60Hz | 854×480 50Hz | 640×480 60Hz |
X offset | 96 | 202 | 96 |
Width | 854 | 854? | 640? |
Y offset | 8 | 8 | 8 |
Height | 480 | 480? | 480? |
0xF0009400 | 0x03B00417 | 0x01AC04EB | 0x03B00417 |
0xF0009404 | 0x01B201FE | 0x01BD01FD | 0x01B201FE |
0xF0009408 | 32 | 32 | 32 |
0xF000940C | 8 | 8 | 8 |
0xF0009410 | 96 | 202 | 96 |
0xF0009414 | 8 | 8 | 8 |
0xF0009418 | 950 | 1056 | 950 |
0xF000941C | 488 | 488 | 488 |
0xF0009420 | 96 | 202 | 203 |
0xF0009424 | 854 | 854 | 640 |
0xF0009428 | 8 | 8 | 8 |
0xF0009480 | 0x2 | 0x2 | 0xA |
0xF0009508 | 0x8 | 0x8 | 0x8 |
0xF000950C | 0xB2 | 0xB2 | 0xB2 |
0xF0009510 | 0x15C | 0x15C | 0x15C |
0xF0009514 | 0x7FF | 0x7FF | 0x7FF |