What is the component that allows the cartridge to hold more ROM or RAM?
MBC - Memory bank controller
DMG
Original GameBoy - originally "Dot Matrix Game"
SGB
Super GameBoy - SNES plug-in cartridge
CGB
GameBoy Color
RGBDS
(rednex) GameBoy Development System. de-facto assembly language programming environment for modern GameBoy programming
Pandocs
Extensive gameboy technical reference
DMG-01
Original original gameboy model number
Cartridge
Physical container of the program - along optionally with an MBC and ERAM
Console
The hardware you hold in your hand to play a game
D-Pad
The four-way controller. Can do diagonals (e.g. TOP-LEFT), but not TOP-BOTTOM
Select Button
The select button on the Joypad. Uses of Select is to change settings, switch options, or toggle items inside of games. Used for menu navigation and in-game actions. Can also be used as a shortcut.
Joypad
Collective name for D-Pad, select, start, and A/B buttons
Active Components
Things that actually do stuff. Composed of the CPU and PPU
CPU
You know what this is
PPU
Picture Processing Unit. Responsible for displaying graphics on the LCD. Uses VRAM and OAM to do its work
ROM
On the cartridge
Rom Image
The code and assets compiled and then put on to a cartridge
ERAM
External RAM, optional ram on the cartridge. Needs an MBC to work. Typically used for battery-backed-up save states
MBC
Memory Bank Controller, allows for extended ROM and RAM on a cartridge via bank switching
VRAM
Video RAM. 8K
WRAM
Work RAM. 8K
HRAM
High RAM. Small (127 bytes) work area, along with smaller/faster instructions for access
OAM
Object-Attribute Memory (160 bytes). Contains sprite configuration settings
Sprite
independently movable object. like characters or projectiles
I/O Registers
128 Bytes. How to commnicate with internal devices. Such as LCD, joypad, timers, serial interface, and the speaker
IE
Interrupt-enable register. Five bits are significant (TBDiscussed). 8 bits
Memory Map
Addresses where the passive components are located in memory
What memory is used by the PPU?
VRAM and OAM
ROM memory map
0000...7FFF (cartridge). 32K. Instructions and assets
VRAM memory map
8000...9FFF (console). 8K. Stores graphics and control for PPU
ERAM memory map
A000...BFFF (cartridge). 8K. External RAM, often used for game saves
WRAM memory map
C000...DFFF (console). 8K. Working RAM
OAM memory map
FE00...FE9F (console). 160 bytes. Sprite attributes
I/O memory map
FF00...FF7F (console). 128 bytes. Control registers for internal devices
HRAM memory map
FF80...FFFE (console). 127 bytes. Temporary data storage
IE memory map
FFFF...FFFF (console). 1 byte. interrupt-enable register
Tile
8x8 chunk of graphics.
each row is two bytes (8 pixels * two colors)
16 bytes total
(encoding is another card)
Tile encoding
Tiles are “interleaved tile planar”
For each row, assuming colors bits are arranged
B7 B6 | B5 B4 | B3 B2 | B1 B0 and D7 D6 | D5 D4 | D3 D2 | D1 D0
the first actual byte has the least significant bits
the second actual byte hsa the most significant bits
FInal layout:
B6 B4 B2 B0 D6 D4 D2 D0 | B7 B5 B3 B1 D7 D5 D3 D1
Colors
Two bits.
00 white
01 light gray
10 dark gray
11 black
Palette
one byte. Four colors * 2 bits
INDEX 3 2 1 0
Colors: B7 B6 | B5 B4 | B3 B2 | B1 B0
The indirection lets us change colors around without having to change a bunch of VRAM
Tile Area
Not an official name.
6K region in VRAM - $8000-$97FF
Tiles are 16 bytes, so this is 384 tiles available at any one time
Indexing is … unique. Another card
Describe Tile Area Addressing Modes
The tile region is 6K, at 16 bytes per tile, is 384 tiles
384 is also 128 * 3.
So the tile storage area is split into three 128-index regions (sixten bytes, so 2K per bank:
Block 1 $8000 - $87FF - indexes UNSIGNED, cover first two blocks
Block 2 $8800 - $8FFF
Block 3 $9000 - $97FF - indexes UNSIGNED based on $9000 - covers second two blocks
Addressing mdoe $8000 is unsigned indexes, covering first two blocks
Addressing mode $8800 is signed indexes, based on $9000
Means Block 2 is covered by both.
Bitwise, the indexes in block 2 are identical
Tilemap
32x32 collection of tile indicies. 32 x 32 x 1 = 1k
There are two tilemaps avilable.
So 2K of tilemap plus 6K of tiles = 8K of VRAM
What are the three high-level graphic concepts
Background
Window
Sprites (Objects)
Talk to me about the Background
256 x 256 pixels
32 x 32 tiles
lives in VRAM
Scrolls
Wraps
Defined by a tilemap
Tell me about Window
160 x 144 area (size of screen)
20 x 8 tiles
no scroll
no wrap
defined by a tile map
no transparency
rendered over background
usually used for UI
Tell me about Sprites
a.k.a. Objects for e.g. players and projectiles
8x8 (one tile) or 8x16 (two tiles, stacked vertically) in size
lives in OAM
40 sprites max (160 / 40)
pixel locations, rendered on top of background and window
has transparency
can v/h flip
has priority flag with BG (see Object Attribute card)
two palettes
Sprite Attributes
X, Y
Tile Index
Palette 0 or 1
control flags
control flags are
Priority
X flip
Y flip
Palette 0 / Palette 1
What is VBLANK
10 lines of scanline-time where VRAM is available for changes.
Can detect by looking at `rLY` (register, Line Y) to equal 144 (so one off the botttom of the screen (polling)
Or using HALT + Interrupt (deets on another card)
How do you scroll the background
set registers rSCX and rSCY
tell me about VBLANK Halt + Interrupt
HALT puts the device into low-power state. CPU stops, PPU continues
So, set up an interrupt handler for VBLANK. Then when doing a frame, perform your work, then HALT. When VBLANK happens, you’ll pick up at the same place.
code!
; init
ld a, IEF_VBLANK
ld [rIE], a
ei
; section
section “vblank_interrupt”, [$0040]
reti
; frame handler
halt
;; then do VRAM-related work
;; then do game logic while screen is using VRAM
What are some display timings
160 x 144 pixels
“refresh” is one complete update of screen
144 M-Cycles per line (108.7 µs)
17,556 m-cycles per frame. - 15.67 ms
VBLANK is 10 lines of nop, 1.08 ms
“frame” is screen + vblank
59.73 fps
rBGP
I/O register
Background Palette (one byte)
rLCDC
LCD Control
LCDCF flags
flags for rLCDC
(first line is bit clear, second line is if it is set. number is bit number)
7 LCDCF_OFF — LCD On/Off
LCDCF_ON
6 LCDCF_WIN9800 — Window tile map
LCDCF_WIN9C00
5 LCDCF_WINOFF — Window display
LCDCF_WINON — requires BGON
4 LCDCF_BG8800 — BG and WIndow tile data select
LCDCF_BG8000 — (a.k.a. addressing mode)
3 LCDCF_BG9800 — BG tile map select
LCDCF_BG9C00
2 LCDCF_OBJ8 — square sprites (8x8)
LCDCF_OBJ16 — tall sprites (8x16)
1 LCDCF_OBJOFF — display sprites (big switch)
LCDCF_OBJON
0 LCDCF_BGOFF — backgroud on/off
LCDCF_BGON
rLY
Current scanline the PPU is processing
rSCX / rSCY
scroll X/Y position
rIE
interrupt enable mask.
IEF_VBLANK
IEF_STAT
IEF_TIMER
IEF_SERIAL
IEF_HILO
rWX / rWY
Window position
Window position limitations
The window is offset by 7 pixels. So X=7 is the left hand positon of the screen.
Don’t use an X of 0…6 - ends up turning negative, which then gets treated as unsigned. So start with 7
Don’t use an X of 166 - precisely one vertical slice of visible pixels, triggers hardware bug
rOBP0 / rOBP1
I/O registers
Set the object (sprite) palette zero and palette one
Offset macros for sprites
OMA_X
OMA_Y
OMA_TILEID
OMA_FLAGS
Sprite Colors
Color at index zero of palette is treated as transparent,
so you get three colors
Can set the Priority bit. if set, the background (index) colors 1…3 overwrite the sprite, and color index zero lets it show through
Sprite limitations
only 40 sprites (160 bytes with 4 bytes per sprite)
only 10 per a scanline (rest are ignored)
can’t make invisible via flags - have to move offscreen to hide. (do it vertically so you don’t consume sprites on a scanline)
How to make “data structures”
Use rsreset to change • to zero
Make a set of symbols for the fields of the “struct”, e.g.
def PREFIX_FIELD1 rb 1
def PREFIX_FIELD2 rb 2
…
def sizeof_PREFIX rb 0
Each PREFIX_FIELD symbol turns into an offset from a base pointer
sizeof_PREFIX is the size of the structure
use PREFIX for namespacing
How to make global variables (especially when using a struct)
Use rsset to change • to an address
For simple globals, do a def NAME rb #
For structus, do def NAME rb sizeof_PREFIX
How to reset • to zero
rsreset
How to set • to an address
rsset $ADDRESS
changes • to zero
rsset
changes • to an address. Handy for placing bytes at particular places in memory, or to start aggregating a list of global variables
Storage reservation sizzes
rb - one byte
rw - one word (two bytes)
rl - one long (four bytes)
What is the register used for reading held state of the gameboy’s keys
rP1
Name comes from “I/O Port On” on the circuit diagrams.
What are the symbols for reading gameboy’s keys
Set rP1 to
P1F GET DPAD to 1 to strobe the direction keys
P1F GET BTN to 1 to strobe the buttons
set to GET_NONE to to 1s to turn off the strobe
What is rP!’s layout?
bit# what it does
7 unused
6 unused
5 key select (GET_DPAD)
4 key select (GET_BTN)
3,2,1,0 - the pressed values. ZERO IS BUTTON IS DOWN
The pressed values depend on which key select mode is used
either Down/Up/Left/Right, or Start/Select/B/A (in order)
How are keypad buttons usually organized
Do two strobes. Put the dpad into the high-order nibbage, put the buttons into the low-order nibbage.
Then use the symbols
PADF or PADB with DOWN
with UP
LEFT
RIGHT
START
SELECT
B
A
The PADF-underscore-DOWN/UP/etc are flags
the PADB-underscore-DOWN/UP/etc are bit numbers
What is the bit flag value in rP1 when a key is pressed
Key-down means flag is cleared, a zero value.
Known as “negative logic”
What are the two ways of checking a key pressed value
AND works only with the accumulator, but can work with multiple flags at once
and a, PADF UP | PADF B
jr nz, .skip
(handle up/B)
.skip
Recall that button-down is cleared flag, so the AND will end up being all zeroes if both of the buttons are down. So jump nz to skip over the work
OR works with any 8-bit register, but works with a singl flag at a time
or PADF UP | a
(handle up)
How many dummy loads do you put after a rP1 strobe before reading? And why?
for DPAD, need one dummy load (total of two) of [rP1] before getting the value. For Buttons, need five dummy loads (total of six) before getting the value.
It takes some time for the circuitry to settle - line switching stabalization (not debouncing). The loads are actually just a delay, but is idiomatic
Keypress handle vs interrupts or polling?
Polling is recommended
Can use interrupt (IEF_HILO - $0040), but you can only get told of which keys change state in the four lower bits of rP1. So you can have aliasing if you look for all keys (e.g. RIGHT and B share a bit)
Plus interrupts can bounce a lot.
Interrupts can be useful for waking up from a HALT on user input if you’re going to be sleeping for more than a frame, perhaps due to a pause screen or a low-impact puzzle game
Last changed9 hours ago