Skip to content
Shane DeSeranno edited this page Nov 5, 2015 · 12 revisions

Go Home

Part 12 - GPU

This is a huge can of worms. But at the end of the day, the entire purpose of this device is to arrange bytes into a picture. We are only implementing the classic Gameboy (no color). This makes our job a bit easier.

The Control Register (0xFF40)

This register is used to control the LCD screen.

Bit 7: LCD Display Enable             (0=Off, 1=On)
Bit 6: Window Tile Map Display Select (0=0x9800-0x9BFF, 1=0x9C00-0x9FFF)
Bit 5: Window Display Enable          (0=Off, 1=On)
Bit 4: BG & Window Tile Data Select   (0=0x8800-0x97FF, 1=0x8000-0x8FFF)
Bit 3: BG Tile Map Display Select     (0=0x9800-0x9BFF, 1=0x9C00-0x9FFF)
Bit 2: OBJ (Sprite) Size              (0=8x8, 1=8x16)
Bit 1: OBJ (Sprite) Display Enable    (0=Off, 1=On)
Bit 0: BG Display                     (0=Off, 1=On)

For example, during the boot sequence:

LD A, $91           ; $005b
LD ($FF00+$40), A   ; $005d  Turn on LCD, showing Background

This loads 0x91 into the 0xFF40 control register. This is 1001 0001 in binary. So bit 7, 4, and 0 are set to 1. Everything else is 0. This performs all of these actions:

  • Turns on the LCD display
  • Selects 0x9800-0x9BFF as the tile map
  • Disables window display
  • Selects 0x8000-0x8FFF for the BG & Window tile data
  • Selects 0x9800-0x9BFF for the BG tile map data
  • Sets OBJ size to 8x8
  • Disables OBJ display
  • Enables BG display

LCD Status Register (0xFF41)

This register query for a variety of LCD statuses. The bits are:

Bit 6: LYC=LY Coincidence Interrupt (1=Enable) (Read/Write)
Bit 5: Mode 2 OAM Interrupt         (1=Enable) (Read/Write)
Bit 4: Mode 1 V-Blank Interrupt     (1=Enable) (Read/Write)
Bit 3: Mode 0 H-Blank Interrupt     (1=Enable) (Read/Write)
Bit 2: Coincidence Flag  (0:LYC<>LY, 1:LYC=LY) (Read Only)
Bit 1-0: Mode Flag       (Mode 0-3, see below) (Read Only)
        0: During H-Blank
        1: During V-Blank
        2: During Searching OAM-RAM
        3: During Transfering Data to LCD Driver

Bit 6 is used to enable a CPU interrupt when the LCD screen is redrawing a specific line (LY=0xFF44) and the game can specify the line with the LYC register (0xFF45). Bit 2 will be enabled when LYC=LY and disabled otherwise. Bit 1/0 indicate the current mode the LCD device is in. More details on the LCD status can be found here.

LCD Position and Scrolling Registers

0xFF42: Scroll Y (R/W) 0xFF43: Scroll X (R/W) These specify the position in the 256x256 pixel BG map, which point is displayed at the upper-left LCD display position. The values range from 0-255 (0x00 to 0xFF). The video controller automatically wraps back to the upper-left position in BG map when drawing exceeds the lower-right border of the BG map area.

0xFF44: Y-Coordinate (R) This register indicates the current vertical line that has data transferred to the LCD Driver. This register can take on any value between 0 through 153 (0x00-0x99). The values between 144 and 153 (0x90-0x99) indicate the V-Blank period where the display rests finishes a full refresh. Any writing to this register will reset the counter.

0xFF45: LY Compare (R/W) The Gameboy constantly compares the value of the 0xFF44 and 0xFF45 registers. When both values are identical, the coincidence bit in the status register (0xFF41) becomes set, and a STAT interrupt is requested.

0xFF4A: Window Y Position (R/W) 0xFF4B: Window X Position minus 7 (R/W) This register specifies the upper-left positions of the window area. The window is an alternate background area which can be displayed above of the normal background. OBJs (sprites) may be still displayed above or behind the window, just as for normal BG. The window becomes visible when positions are set in range WX=0..166, WY=0..143. A position of WX=7 and WY=0 locates the window at upper left, it is then completely covering normal background.

LCD Monochrome Palettes

0xFF47: BG Palette Data (R/W) This register assigns gray shades to the color numbers of the BG and Window tiles.

Bit 7-6: Shade for Color Number 3
Bit 5-4: Shade for Color Number 2
Bit 3-2: Shade for Color Number 1
Bit 1-0: Shade for Color Number 0

The four possible gray shades are:

0: White
1: Light gray
2: Dark gray
3: Black

0xFF48: Object Palette 0 Data (R/W) 0xFF49: Object Palette 1 Data (R/W) These registers assigns gray shades for sprite palette 0 and 1. They work exactly as BG Palette Data (0xFF47), except that the lower two bits aren't used because sprite data 00 is transparent.

LCD OAM DMA Transfers

0xFF46: DMA Transfer and Start Address (W) Writing to this register launches a DMA transfer from ROM/RAM to OAM memory (sprite attribute table). The written value specifies the transfer source address divided by 100h.

Source:      0xZZ00-0xZZ9F   ;ZZ in range from 0x00-0xF1
Destination: 0xFE00-0xFE9F

VRAM Tile Data

Tile Data is stored in VRAM at addresses 0x8000-0x97FF. This area defines the Bitmaps for 192 Tiles. Each tile is 8x8 pixels and has a color depth of four gray shades. Tiles can be displayed as part of the Background/Window map, and as OAM tiles (foreground sprites). Foreground sprites may have only 3 colors, because color 0 is transparent. There are two Tile Pattern Tables at 0x8000-0x8FFF and at 0x8800-0x97FF. The first table can be used for sprites and the background with tiles are numbered from 0 to 255 (0x00-0xFF). The second table can be used for the background and the window display and has tiles are numbered from -128 to 127 (0x80-0x7F).

Each Tile occupies 16 bytes, where each 2 bytes represent a line:

Byte 00-01: First Line (Upper 8 pixels)
Byte 02-03: Second Line
...
Byte 0C-0D: 7th Line
Byte 0E-0F: Last Line (Bottom 8 pixels)

For each line, the first byte defines the least significant bits of the color numbers for each pixel, and the second byte defines the upper bits of the color numbers. In either case, Bit 7 is the leftmost pixel, and Bit 0 the rightmost. So, each pixel is having a color number in range from 0-3. The color numbers are translated into gray shades depending on the current palettes. The palettes are defined through registers 0xFF47-0xFF49.

VRAM Background Maps

The Gameboy contains two 32x32 tile background maps in VRAM at addresses 0x9800h-0x9BFF and 0x9C00-0x9FFF. Each can be used either to display normal background, or window background.

BG Map Tile Numbers

An area of VRAM known as Background Tile Map contains the numbers of tiles to be displayed. It is organized as 32 rows of 32 bytes each. Each byte contains a number of a tile to be displayed. Tile patterns are taken from the Tile Data Table located either at 0x8000-0x8FFF or 0x8800-0x97FF. In the first case, patterns are numbered with unsigned numbers from 0 to 255. In the second case, patterns have signed numbers from -128 to 127. In this case pattern #0 lies at address 0x9000. The Tile Data Table address for the background can be selected via control register (0xFF40).

Normal Background (BG)

The Scroll Y and Scroll X registers can be used to scroll the background, allowing you to select the origin of the visible 160x144 pixel area within the total 256x256 pixel background map. Backgrounds wraps around the screen (i.e. when part of it goes off the screen, it appears on the opposite side.)

The Window

Besides background, there is also a window overlaying the background. The window is not scrollable. The location of a window on the screen can be adjusted via Window X and Window Y registers. Screen coordinates of the top left corner of a window are Window X-7, Window Y. The tiles for the window are stored in the Tile Data Table. Both the background and the window share the same Tile Data Table.

Both background and window can be disabled or enabled separately via bits in the control register (0xFF40).

VRAM Sprite Attribute Table (OAM)

The Gameboy video controller can display up to 40 sprites either at 8x8 or 8x16 pixels. Because of a limitation of hardware, only ten sprites can be displayed per scan line. Sprite patterns have the same format as BG tiles, but they are taken from the Sprite Pattern Table located at 0x8000-0x8FFF and have unsigned numbering.

Sprite attributes reside in the Sprite Attribute Table (OAM - Object Attribute Memory) at 0xFE00-0xFE9F. Each of the 40 entries consists of four bytes with the following meanings:

Byte0: Y Position - Specifies the sprites vertical position on the screen (minus 16).  An off-screen value (for example, Y=0 or Y>=160) hides the sprite.
Byte1: X Position - Specifies the sprites horizontal position on the screen (minus 8). An offscreen value (X=0 or X>=168) hides the sprite, but the sprite still affects the priority ordering.  A better way to hide a sprite is to set its Y-coordinate off-screen.
Byte2: Tile/Pattern Number - Specifies the sprites Tile Number (0x00-0xFF). This unsigned value selects a tile from memory at 0x8000-0x8FFF.  In 8x16 mode, the lower bit of the tile number is ignored.
Byte3: Attributes/Flags
    Bit7: OBJ-to-BG Priority (0=OBJ above BG, 1=OBJ behind BG color 1-3).  Used for both BG and Window. BG color 0 is always behind OBJ.
    Bit6: Y flip          (0=Normal, 1=Vertically mirrored)
    Bit5: X flip          (0=Normal, 1=Horizontally mirrored)
    Bit4: Palette number  (0=OBP0, 1=OBP1)
    Bit3-0: Unused

Sprite Priorities and Conflicts

When sprites with different X coordinate values overlap, the one with the smaller X coordinate (closer to the left) will have priority and appear above any others. When sprites with the same X coordinate values overlap, they have priority according to table ordering. (i.e. 0xFE00 - highest, 0xFE04 - next highest, etc.)

Only 10 sprites can be displayed on any one line. When this limit is exceeded, the lower priority sprites (priorities listed above) won't be displayed. To keep unused sprites from affecting onscreen sprites set their Y coordinate to Y=0 or Y=>144+16. Just setting the X coordinate to X=0 or X=>160+8 on a sprite will hide it but it will still affect other sprites sharing the same lines.

Writing Data to OAM Memory

The recommended method is to write the data to normal RAM first, and to copy that RAM to OAM by using the DMA transfer function, initiated through DMA register (0xFF46). It is also possible to write data directly to the OAM area by using normal LD commands, this works only during the H-Blank and V-Blank periods. The current state of the LCD controller can be read out from the STAT register (0xFF41).

Summary

That was a lot of information, but all of those pieces provides all of the detail needed to render an image to the screen. Essentially drawing background, window, and sprites in the correct order and offset with the right palette! All of this gets stuffed into a small image that can be rendered.

Clone this wiki locally