Changes

Jump to navigation Jump to search
6,540 bytes added ,  18:38, 18 April 2021
Add 2DS info to "scanline double"
Line 2: Line 2:     
== Map ==
 
== Map ==
 +
Address mappings for the external registers. GSPGPU:WriteHWRegs takes these addresses relative to 0x1EB00000.
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
! User VA
 
! User VA
Line 30: Line 31:  
| 0x10400030
 
| 0x10400030
 
| 4
 
| 4
| ?
+
| VRAM bank control
|
+
| Bits 8-11 = bank[i] disabled; other bits are unused
 
|-
 
|-
 
| 0x1EF00034
 
| 0x1EF00034
Line 74: Line 75:  
| [[#Transfer_Engine|Transfer Engine]] "DMA"
 
| [[#Transfer_Engine|Transfer Engine]] "DMA"
 
|
 
|
 +
|-
 +
|colspan="5"| 0x1EF01000/0x10401000 - 0x1EF01C00/0x10401C00 maps to [[GPU/Internal_Registers|GPU internal registers]]. These registers are usually not read/written directly here, but are written using the command list interface below (corresponding to the GPUREG_CMDBUF_* internal registers)
 
|-
 
|-
 
| 0x1EF01000
 
| 0x1EF01000
Line 135: Line 138:     
== LCD Source Framebuffer Setup ==
 
== LCD Source Framebuffer Setup ==
 +
 +
All of these registers must be accessed with 32bit operations regardless of the registers' actual bit size.
 +
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
! Offset
 
! Offset
! Length
   
! Name
 
! Name
 
! Comments
 
! Comments
 
|-
 
|-
 
| 0x00
 
| 0x00
| 4
+
| H-total (V-total on not physically rotated screens).
| Pixel timer (not pixel clock)
+
| 12bits.
| Higher values are slower, min. 0x1C1, bitmask 0xFFF
+
 
 +
Setting this value too low will make the screen not be able to sync any pixels other than a single one from the wrong location. The lowest the screen can handle is 0x1C2, at 0x1C1 the display loses a few scanlines worth of pixel clock (though not noticable).
 
|-
 
|-
 
| 0x04
 
| 0x04
| 4
+
| HBlank timer(?)
| VScanStart(?)
+
| Seems to determine the horizontal blanking interval.
| Values 0xD1-0x1C1 inclusive are valid (except 2DS bottom screen)
+
 
min. 0xD1, bitmask 0xFFF
+
 
 +
Setting this to lower than <code>HTotal - HDisp</code> will make the screen not catch up with the scanlines, some will be skipped, some will be misaligned.
 +
 
 +
Setting this to higher than <code>HTotal - HDisp</code> will make the displayed image misaligned to the right.
 +
 
 +
Setting this to higher than <code>HTotal</code> seems to make the horizontal synchronization never happen.
 
|-
 
|-
 
| 0x08
 
| 0x08
| 4
   
| ?
 
| ?
|  
+
| must be >= REG#0x00
 
|-
 
|-
 
| 0x0C
 
| 0x0C
| 4
   
| ?
 
| ?
|  
+
| must be >= REG#0x08
 
|-
 
|-
 
| 0x10
 
| 0x10
| 4
+
| Window X start (LgyFb)
| VAdjustGranule
+
| Offsets the viewing window on the display's physical X co-ordinate relative to its front porch end.
 
  −
or
  −
HAdjust(2DS bottom screen)
  −
| Finetune vertical pixel offset, 0x1C2 max = half pixel
     −
or
+
Outside of LgyFb changing this value only seems to cause weird pixel interpolation and blurryness.
offset the bottom screen (0 to kill 2DS top screen, 0x1C2 max on bottom screen)
   
|-
 
|-
 
| 0x14
 
| 0x14
| 4
+
| Window X end (LgyFb)
| HEndOffset(?) (poor 2DS emulation)
+
| Window X start + window width - 1 is written here to set the end display scan pixel offset.
| Moves the frame left/right(after some conditions are met)
     −
default value is 0xCF
+
Outside of LgyFb it seems to offset the screen to the left if this value is high enough, but can glitch out the syncing on the bottom screen. High enough values will make the screen skip too many "pixels". If this value is higher or equal to *some value* (aka. if less than one pixel per line is displayed on the screen) then the screen will lose synchronization.
 
|-
 
|-
 
| 0x18
 
| 0x18
| 4
+
| Window Y start (LgyFb)
| ???
+
| Offsets the viewing window on the display's physical Y co-ordinate relative to the first visible scanline.
|  
   
|-
 
|-
 
| 0x20
 
| 0x20
| 4
+
| Low: Window Y end (LgyFb)
| ?
+
High: ???
| ??? the screen gets vertically offset with wrap-around
+
| Low: Window Y start + window height - 1 is written here to set the last display scanline relative to the first visible scanline.
horizontal timing gets messed up
+
 
 +
High: This is cleared to zero when displaying LgyFb. Outside of LgyFb this doesn't really seem to do anything useful.
 +
 
 +
 
 +
??? extra pixels get inserted in the first displayed scanline and thus the image gets shifted to the right. Seems to make horizontal syncing a bit glitchy. If a HSync occurs, the pixel data is suspended until the first pixel is supposed to be displayed, then the pixel stream will continue where it left off until a delayed HSync gets processed relative to the pixel data.
 
|-
 
|-
 
| 0x24
 
| 0x24
| 4
+
| V-total (H-total on not physically rotated screens).
| HSync timer?
+
| Total scanlines including porches/sync timing. Setting this to 494 for the topscreen lowers framerate to about 50.040660858 Hz.
|  
   
|-
 
|-
 
| 0x28
 
| 0x28
| 4
+
| VBlank timer(?)
| VStart(?)
+
| Seems to determine the vertical blanking interval.
|
+
 
 +
 
 +
Setting this to lower than <code>VTotal - VDisp</code> will cut off the top <code>VTotal - VDisp - thisvalue</code> lines.
 +
 
 +
Setting this to higher than <code>VTotal - VDisp</code> will make the image be pushed downwards with the overscan color visible.
 +
 
 +
Setting this to higher than <code>HTotal</code> will make the GPU skip vertical pixel data synchronization (hence filling the screen with the rest of the pixel data past the given screen framebuffer size). Also will skip <code>thisvalue + somevalue - HTotal</code> lines into the "global" pixel buffer.
 
|-
 
|-
 
| 0x30
 
| 0x30
| 4
   
| VTotal
 
| VTotal
| Total amount of vertical scanlines
+
| Total amount of vertical scanlines in the pixel buffer, must be bigger than *an unknown blanking-like value*. If this value is less than VDisp then the last two scanlines will be repeated interlaced until VDisp is reached.
 
|-
 
|-
 
| 0x34
 
| 0x34
| 4
+
| VDisp(?)
| VDisp
+
| Total amonut of vertical scanlines displayed (only for top screen it seems like). If this value is less than VTotal then the rest of the scanlines will not be updated on the screen, so those will slowly fade out. Must be bigger than *an unknown blanking-like value*, otherwise an underflow will happen.
| Total amonut of vertical scanlines displayed
+
|-
 +
| 0x38
 +
| Vertical data offset(?)
 +
| ??? Seems to offset the screen upwards if this value is high enough. If this value is higher or equal to *some value* (aka. if less than one scanline is displayed on the screen) then the screen will lose synchronization.
 
|-
 
|-
 
| 0x44
 
| 0x44
| 4
   
| ???
 
| ???
 
| similar functionality to 0x10
 
| similar functionality to 0x10
 +
|-
 +
| 0x48
 +
| ???
 +
| bit0 seems to disable HSync, bit8 seems to disable VSync, rest of the bits aren't writable.
 
|-
 
|-
 
| 0x4C
 
| 0x4C
| 4
   
| Overscan filler color
 
| Overscan filler color
 
|  
 
|  
 
|-
 
|-
 
| 0x50
 
| 0x50
| 4
+
| Horizontal position counter
| Vertical scanline counter
   
| read-only
 
| read-only
 
|-
 
|-
 
| 0x54
 
| 0x54
| 4
+
| Horizontal scanline (HBlank) counter
| Horizontal scanline counter
   
| read-only
 
| read-only
 
|-
 
|-
 
| 0x5C
 
| 0x5C
| 4
   
| ???
 
| ???
 
| low u16: framebuffer width
 
| low u16: framebuffer width
Line 238: Line 250:  
|-
 
|-
 
| 0x60
 
| 0x60
| 4
   
| ???
 
| ???
 
| low u16: timing data(?)
 
| low u16: timing data(?)
Line 244: Line 255:  
|-
 
|-
 
| 0x64
 
| 0x64
| 4
   
| ???
 
| ???
 
| low u16: unknown
 
| low u16: unknown
Line 250: Line 260:  
|-
 
|-
 
| 0x68
 
| 0x68
| 4
   
| Framebuffer A first address
 
| Framebuffer A first address
 
| For top screen, this is the left eye 3D framebuffer.
 
| For top screen, this is the left eye 3D framebuffer.
 
|-
 
|-
 
| 0x6C
 
| 0x6C
| 4
   
| Framebuffer A second address
 
| Framebuffer A second address
 
| For top screen, this is the left eye 3D framebuffer.
 
| For top screen, this is the left eye 3D framebuffer.
 
|-
 
|-
 
| 0x70
 
| 0x70
| 4
   
| Framebuffer format
 
| Framebuffer format
 
| Bit0-15: framebuffer format, bit16-31: unknown
 
| Bit0-15: framebuffer format, bit16-31: unknown
 +
|-
 +
| 0x74
 +
| PDC control
 +
| Bit 0: Enable display controller.
 +
Bit 8: H(Blank?) IRQ mask (0 = enabled).
 +
Bit 9: VBlank IRQ mask (0 = enabled).
 +
Bit 10: Error IRQ mask? (0 = enabled).
 +
Bit 16: Output enable?
 
|-
 
|-
 
| 0x78
 
| 0x78
| 4
+
| Framebuffer select and status
| Framebuffer select
+
| Bit 0: Next framebuffer to display (after VBlank).
| Bit0: which framebuffer to display, bit1-7: unknown
+
Bit 4: Currently displaying framebuffer?
 +
Bit 8: Reset FIFO?
 +
Bit 16: H(Blank?) IRQ status/ack. Write 1 to aknowledge.
 +
Bit 17: VBlank IRQ status/ack.
 +
Bit 18: Error IRQ status/ack?
 +
|-
 +
| 0x80
 +
| Color lookup table index select
 +
| 8bits, write-only
 
|-
 
|-
 
| 0x84
 
| 0x84
| 4
+
| Color lookup table indexed element
| Color adjustment register
+
| Contains the value of the color lookup table indexed by the above register, 24bits, RGB8 (0x00BBGGRR) 
| Each poke changes the color blended over the screens content randomly.
+
Accessing this register will increase the index register by one
 
|-
 
|-
 
| 0x90
 
| 0x90
| 4
   
| Framebuffer stride
 
| Framebuffer stride
 
| Distance in bytes between the start of two framebuffer rows (must be a multiple of 8).
 
| Distance in bytes between the start of two framebuffer rows (must be a multiple of 8).
 
|-
 
|-
 
| 0x94
 
| 0x94
| 4
   
| Framebuffer B first address
 
| Framebuffer B first address
 
| For top screen, this is the right eye 3D framebuffer. Unused for bottom screen.
 
| For top screen, this is the right eye 3D framebuffer. Unused for bottom screen.
 
|-
 
|-
 
| 0x98
 
| 0x98
| 4
   
| Framebuffer B second address
 
| Framebuffer B second address
 
| For top screen, this is the right eye 3D framebuffer. Unused for bottom screen.
 
| For top screen, this is the right eye 3D framebuffer. Unused for bottom screen.
Line 302: Line 322:  
| ?
 
| ?
 
|-
 
|-
| 4
+
| 5-4
| Unused?
+
| Framebuffer scanline output mode (interlace config)
|-
+
 
| 5
+
0 - A  (output image as normal)
| Enable parallax barrier (i.e. 3D).
+
1 - AA (output a single line twice, aka framebuffer A is interlaced with itself)
 +
2 - AB (interlace framebuffer A and framebuffer B)
 +
3 - BA (same as above, but the line from framebuffer B is outputted first)
 +
 
 +
0 is used by bottom screen at all times.
 +
1 is used by the top screen in 2D mode.
 +
2 is used by top screen in 3D mode.
 +
3 goes unused in userland.
 
|-
 
|-
 
| 6
 
| 6
| 1 = main screen, 0 = sub screen. However if bit5 is set, this bit is cleared.
+
| Scan doubling enable?* (used by top screen)
 
|-
 
|-
 
| 7
 
| 7
Line 320: Line 347:  
| Unused?
 
| Unused?
 
|}
 
|}
 +
 +
* The weird thing about scan doubling, is that it works different between the bottom and top LCD. On the bottom LCD, it doubles the number of outputted pixels (so the same pixel is outputted twice, effectively doing column doubling). However on the top screen, it does scanline doubling instead. Considering that the bottom screen's table doesn't work on the top screen, this could give a hint as to how the top screen receives the pixel data from the PDC.
 +
On a 2DS, it seems to have no effect on the top part of the display, and on the bottom screen it just shifts the framebuffer to the right two pixels.
 +
    
GSP module only allows the LCD stereoscopy to be enabled when bit5=1 and bit6=0 here. When GSP module updates this register, GSP module will automatically disable the stereoscopy if those bits are not set for enabling stereoscopy.
 
GSP module only allows the LCD stereoscopy to be enabled when bit5=1 and bit6=0 here. When GSP module updates this register, GSP module will automatically disable the stereoscopy if those bits are not set for enabling stereoscopy.
 +
 +
 +
When both interlacing and scan doubling are disabled, the full resolution of the top screen (240x800) can be utilized if the PDC registers are updated to accomodate this higher resolution. GSP contains tables for this mode (gsp mode == 1). GSP automatically applies this mode if both bit5 and bit6 are cleared. This is also the default, and the only valid mode for the bottom screen in userland.
 +
 +
If only AB interlacing is enabled, gsp detects this as a request to switch to 3D mode (gsp mode == 2), and enables the parallax barrier.
 +
It's unknown how to control this, but some other PDC registers control if interlacing should be done by true interleaving (both framebuffers are treated as 240x400), or skipping lines (both framebuffers are treated as 240x800)
 +
 +
If only scan doubling is enabled, gsp detects it as a request to switch back to 2D mode for the top screen (gsp mode == 0). This is also the default mode for the top screen.
 +
 +
Both interlacing and scan doubling can't be enabled in usermode, but it works as expected in baremetal.
    
=== Framebuffer color formats ===
 
=== Framebuffer color formats ===
Line 345: Line 386:  
|}
 
|}
 
Color components are laid out in reverse byte order, with the most significant bits used first (i.e. non-24-bit pixels are stored as a little-endian values). For instance, a raw data stream of two GL_RGB565_OES pixels looks like GGGBBBBB RRRRRGGG GGGBBBBB RRRRRGGG.
 
Color components are laid out in reverse byte order, with the most significant bits used first (i.e. non-24-bit pixels are stored as a little-endian values). For instance, a raw data stream of two GL_RGB565_OES pixels looks like GGGBBBBB RRRRRGGG GGGBBBBB RRRRRGGG.
 +
 +
Color formats 5, 6, and 7 are blocked by gsp, but they behave as pixel-doubled RGBA8 (not line doubling, but instead the same pixel is output twice) if used outside of userland.
    
== Transfer Engine ==
 
== Transfer Engine ==
215

edits

Navigation menu