Video summary
Gameboy Emulator Development - Part 06
Main summary
Key takeaways
Main focus of the video (Game Boy emulator dev – Part 06)
This part implements control-flow instructions related to jumping and subroutines, centered around adding a correct CPU stack mechanism first. The emulator needs this to support instructions that push/pop the program counter (PC) for CALL, RET, interrupts, and RST.
1) Stack implementation (core dependency)
The tutorial adds a new stack module:
- New files:
stack.c,stack.h - Stack operations implemented:
stack_push(8-bit)stack_push(16-bit)(pushes high byte then low byte)stack_pop(8-bit)stack_pop(16-bit)(pops high then low, reconstructshigh<<8 | low)
How stack uses emulator state
- Stack pointer (SP) is obtained via a new helper:
cpu_get_regsreturning the CPU register context (ctx->regs)
- Memory access: uses bus reads/writes (
bus.h) - Push behavior:
SP--- write byte to memory at new
SP
- Pop behavior:
- read byte at
SP - then
SP++
- read byte at
Conceptual example explained
- Stack starts at the bottom of working RAM (using
dffe-style addresses). - Pushing values decrements SP and writes values into RAM.
- Popping increments SP and effectively invalidates the popped location (though the memory contents remain).
2) CPU-level PUSH/POP instructions for registers (16-bit)
In cpu_proc.c, the tutorial implements 16-bit register operations:
proc_popandproc_push(only for 16-bit pairs)- Special register-pair behavior for
AF:- When popping into
F/AF, only lower bits (nibble/three-nibble behavior) are kept (masking via a “bottom three nibbles” comment)
- When popping into
- Cycle accuracy:
- cycles increment for each byte transferred
- stack byte operations are called accordingly
Instruction table updates
Adds register-pair variants into the opcode table:
POPfor pairs like BC, DE, HL, AFPUSHfor pairs like BC, DE, HL, AF
3) Generalized jump helper to handle PC pushing
A reusable helper is introduced:
go_to_adder(ctx, address, push_pc_flag)- performs conditional jump logic
- if
push_pc_flagis set, it pushes the current PC onto the stack (16-bit) - adds cycle cost: 2 cycles (one per pushed PC byte)
4) Implementing jump/call/return instructions
Multiple control-flow operations are updated/implemented using the helper:
Jump: JP a16
- Updated to call
go_to_adder(..., false)(does not push PC)
Call: CALL a16
- Uses the same helper with
push_pc_flag = true(pushes PC)
Relative jump: JR r8
- Implements signed relative offset:
- casts the fetched relative value to
charso it can be negative
- casts the fetched relative value to
- target computation:
regs.pc + rel
- jumps via
go_to_adder(..., false)
Return: RET / RETI
RET- checks the condition (
if not ct none) - if the condition passes:
- pops the return address from the stack
- sets
pc
- cycle accuracy matters:
- explicitly mentions popping each byte individually to match timing
- improper cycle behavior can break some games
- checks the condition (
RETI- calls
RET, then re-enables interrupts- sets
master_enable = true
- sets
- uses a
reti = red/ratpattern (based on how it routes toRETlogic)
- calls
5) Instruction table completion for control-flow opcodes
The tutorial adds conditional variants into the opcode instruction array, including:
CALLconditionals:- e.g.,
NZ,NC,Z,C, plus unconditional
- e.g.,
JRconditionals:- e.g.,
NZ,NC,Z,C
- e.g.,
JPconditionals plus specialJP (HL)case:- mentions opcode where the target comes from an address in HL
- aligned with Game Boy’s
JP (HL)behavior
RETconditionals plusRETandRETIvariants
6) Interrupt-like restart: RST
Implements RST instructions:
RSTbehaves like a forced jump to a fixed vector:- vectors like
0x00,0x08,0x10, …0x38
- vectors like
- implemented similarly to
CALL:- pushes PC then jumps to the fixed target
- opcodes added:
- C7–F7, CF–FF (full set for
RST)
- C7–F7, CF–FF (full set for
7) Validation via ROM testing (behavior checks)
The author tests with known ROMs and observes expected control-flow halts:
- One ROM stops at
CB→ implies missingINC/DEC(specifically mentionsHLincrement/decrement weren’t implemented yet) - Tetris ROM stops on decrement path → points to missing
decrementimplementation - DMG Acid ROM stops at
CB→ indicates additional missing instruction(s) (mentionsCBbehavior and the need to implement missing instruction(s))
They conclude Part 06 reaches a good stopping point due to the complexity of jump/push/pop work.
Main speakers / sources
- Primary speaker: “low level devil” (YouTube channel host, presenting Gameboy Emulator Development - Part 06)
- Technical source referenced implicitly:
- emulator codebase modules:
cpu.h,cpu_proc.c,stack.c/.h,bus.h - Game Boy CPU behavior specs for
RET/RETI/CALL/JR/RSTsemantics
- emulator codebase modules: