Video summary
Gameboy Emulator Development - Part 04
Main summary
Key takeaways
Technological focus: Game Boy CPU emulator — instruction fetch/addressing + LD (load) implementation
- The presenter continues from prior parts where some CPU instruction execution and instruction data fetching were already implemented.
- This part concentrates on:
- Fetching the operand/data for all addressing modes (“fetch data function” expansion).
- Implementing all load instructions (the Game Boy
LD/ldinstruction family) and wiring them into the instruction dispatch array.
1) Operand/addressing-mode fetching (cpu fetch.c)
A new file, cpu_fetch.c, is created and the existing CPU context/code is moved/copied into it.
Key additions to operand fetching logic
Handling various operand forms, including:
-
Register + immediate 16-bit addressing:
rd16- Reads immediate bytes as a 16-bit value from the instruction stream (via program-counter patterns).
-
Register-indirect forms
rr: fetch operand from a second register.mmrr/ memory destinations: loading a register value into memory at an address derived from registers.- The fetched data stores whether the destination is memory (
dest_is_mem = true) so the laterLDexecute step knows to write via the bus.
- The fetched data stores whether the destination is memory (
-
Special
LDHhandling involving high memory offsets (FF00 area)- There’s a special-case check for one register type (subtitle says “rtc” but context implies it’s the C register special
LDHbehavior). - Notes about masking/OR-ing with
0xFF00to form a 16-bit address from an 8-bit value. - Uses bus reads and increments CPU cycles when a bus access occurs.
- There’s a special-case check for one register type (subtitle says “rtc” but context implies it’s the C register special
-
HL auto-increment/decrement modes
HLI: read from memory atHL, then incrementHL, and update bus cycles appropriately.HLD: read from memory atHL, then decrementHL.
-
A8immediate / absolute 16-bit related addressing- Fetch operand via program counter and increment PC.
- Covers both directions:
- moving into address/register based on an 8-bit immediate (offset forms)
- moving to/from
A16absolute address forms
-
Special stack-relative instruction
- Implements operand fetch for
LDHL SP+r8(loadHL = SP + signed 8-bit immediate). - Reads an 8-bit immediate from PC, advances PC, updates cycles.
- Implements operand fetch for
-
General immediate byte/word fetching
d8: fetch one byte from PCd16: fetch a 16-bit immediate from PC (low then high bytes combined)
2) Execute-time LD implementation (writing to registers/memory + flags)
A function to perform LD is added/implemented, along with utility helpers.
New helper: cpu_set_reg
Implements register assignment for different register sizes:
- 8-bit registers: writes value with
& 0xFF - 16-bit registers: preserves full word behavior and uses appropriate splitting/reversal logic
bus_read_16 and bus_write_16
In bus.c, the presenter adds:
-
bus_read_16(addr)- Reads low byte at
addr, then high byte ataddr + 1, combines into au16.
- Reads low byte at
-
bus_write_16(addr, value)- Writes high byte and low byte to
addrandaddr + 1in the correct order (as implemented).
- Writes high byte and low byte to
Main LD behavior
In the LD execution logic:
-
Default case
- Writes fetched operand into a destination register.
-
Special case: destination is memory (
dest_is_mem)- Performs a 16-bit bus write when the destination type indicates a 16-bit register/address scenario.
- Uses the fetched value and the computed memory destination via bus.
-
Special case:
LDHL SP+r8flag updates- Computes flags H and C using low-nibble and unsigned carry rules (bitmask checks on
SPand the immediate). - Updates CPU flags (
H,C) and writes registers accordingly:HL = SP + signed(r8)(with explicit casting for signed behavior)
- Computes flags H and C using low-nibble and unsigned carry rules (bitmask checks on
-
Ensures cycle increments occur when memory/bus operations happen.
3) Instruction dispatch table: adding all LD variants
After implementing addressing modes and LD operand fetching/execution, the presenter updates the instruction array to include LD opcodes.
-
Uses the Game Boy opcode table approach:
- Finds all instructions matching
ld(searching “ld” in an instruction set page). - Populates opcode entries with:
- opcode numeric mapping
- addressing mode identifiers (e.g.,
rd16,rr,mmrr,amr, etc.) - register type fields such as
bc,de,hl,a,sp, etc.
- Finds all instructions matching
-
Notes:
- Many
LDopcodes follow systematic patterns (rows/columns); the presenter fills them in programmatically by copying patterns and adjusting register types. - Includes sections like:
- 0x40–0x7F style register-to-register loads (patterns like
b,c,d,e,h,l,m,a, wheremrefers to memory atHL) - 0xE0–0xF style special
LDH/ absolute address variants (e.g.,LDH,LD (a16),A,LD A,(a16))
- 0x40–0x7F style register-to-register loads (patterns like
- Many
4) Testing progress / stopping point
- The presenter runs the emulator and adds temporary logging for bus operations.
-
Observes that execution reaches an “unsupported bus right” beyond the supported range, confirming:
- the
LD/addressing-mode work is being exercised - the emulator correctly fails/halts when encountering bus operations not yet implemented for those ranges
- the
-
Concludes:
- addressing modes and the majority of
LDinstruction handling are integrated - remaining unsupported/unknown instructions exist (e.g., around
e0/ next unknown opcode region)
- addressing modes and the majority of
Declares a “good stopping point” after wiring the load instructions and dispatch table.
Main speakers/sources
- Main speaker: The YouTube presenter (“low-level devil” host) developing a Game Boy emulator in a series titled “Gameboy Emulator Development - Part 04”.