Gameboy Color Complete Technical Reference
Gameboy Color Complete Technical Reference
gekkio
https://gekkio.fi
August 19, 2024
Revision 153
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International
License.
Preface
Caveat
2
How to read this document
🧩 Speculation
This is something that hasn’t been verified, but would make a lot of sense.
Caveat
This explains some caveat about this documentation that you should know.
Warning
3
0.2 Register definitions
In this example:
• After system reset, VALUE is 0b01, BIGVAL is either 0b010 or 0b011, FLAG is 0b1.
• Bits 5 and 0 are unimplemented. Bit 5 always returns 1, and bit 0 always returns 0.
• Both bits of VALUE can be read and written. When this register is written, bit 7 of the written
value goes to bit 1 of VALUE.
• FLAG can only be written to, so reads return a value that is defined elsewhere.
• BIGVAL cannot be written to. Only bits 5-7 of BIGVAL are defined here, so look elsewhere for
the low bits 0-4.
4
Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
How to read this document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
0.1 Formatting of numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
0.2 Register definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2 Clocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1 System clock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
System clock frequency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2 Clock periods, T-cycles, and M-cycles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.1 History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4 Simple model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
5 CPU core timing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
5.1 Fetch/execute overlap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Fetch/execute overlap timing example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6 Sharp SM83 instruction set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
6.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
CB opcode prefix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Undefined opcodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
6.2 8-bit load instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
LD r, r’: Load register (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
LD r, n: Load register (immediate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
LD r, (HL): Load register (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
LD (HL), r: Load from register (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
LD (HL), n: Load from immediate data (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
LD A, (BC): Load accumulator (indirect BC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
LD A, (DE): Load accumulator (indirect DE) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
LD (BC), A: Load from accumulator (indirect BC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
LD (DE), A: Load from accumulator (indirect DE) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
LD A, (nn): Load accumulator (direct) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
LD (nn), A: Load from accumulator (direct) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
LDH A, (C): Load accumulator (indirect 0xFF00+C) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
LDH (C), A: Load from accumulator (indirect 0xFF00+C) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
LDH A, (n): Load accumulator (direct 0xFF00+n) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
LDH (n), A: Load from accumulator (direct 0xFF00+n) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
LD A, (HL-): Load accumulator (indirect HL, decrement) . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
LD (HL-), A: Load from accumulator (indirect HL, decrement) . . . . . . . . . . . . . . . . . . . . . . . 37
LD A, (HL+): Load accumulator (indirect HL, increment) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
LD (HL+), A: Load from accumulator (indirect HL, increment) . . . . . . . . . . . . . . . . . . . . . . . 39
6.3 16-bit load instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5
LD rr, nn: Load 16-bit register / register pair . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
LD (nn), SP: Load from stack pointer (direct) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
LD SP, HL: Load stack pointer from HL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
PUSH rr: Push to stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
POP rr: Pop from stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
LD HL, SP+e: Load HL from adjusted stack pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.4 8-bit arithmetic and logical instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
ADD r: Add (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
ADD (HL): Add (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
ADD n: Add (immediate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
ADC r: Add with carry (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
ADC (HL): Add with carry (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
ADC n: Add with carry (immediate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
SUB r: Subtract (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
SUB (HL): Subtract (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
SUB n: Subtract (immediate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
SBC r: Subtract with carry (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
SBC (HL): Subtract with carry (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
SBC n: Subtract with carry (immediate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
CP r: Compare (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
CP (HL): Compare (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
CP n: Compare (immediate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
INC r: Increment (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
INC (HL): Increment (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
DEC r: Decrement (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
DEC (HL): Decrement (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
AND r: Bitwise AND (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
AND (HL): Bitwise AND (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
AND n: Bitwise AND (immediate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
OR r: Bitwise OR (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
OR (HL): Bitwise OR (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
OR n: Bitwise OR (immediate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
XOR r: Bitwise XOR (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
XOR (HL): Bitwise XOR (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
XOR n: Bitwise XOR (immediate) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
CCF: Complement carry flag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
SCF: Set carry flag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
DAA: Decimal adjust accumulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
CPL: Complement accumulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
6.5 16-bit arithmetic instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
INC rr: Increment 16-bit register . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
DEC rr: Decrement 16-bit register . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
ADD HL, rr: Add (16-bit register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
ADD SP, e: Add to stack pointer (relative) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
6.6 Rotate, shift, and bit operation instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
RLCA: Rotate left circular (accumulator) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
RRCA: Rotate right circular (accumulator) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
RLA: Rotate left (accumulator) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
RRA: Rotate right (accumulator) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
6
RLC r: Rotate left circular (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
RLC (HL): Rotate left circular (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
RRC r: Rotate right circular (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
RRC (HL): Rotate right circular (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
RL r: Rotate left (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
RL (HL): Rotate left (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
RR r: Rotate right (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
RR (HL): Rotate right (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
SLA r: Shift left arithmetic (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
SLA (HL): Shift left arithmetic (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
SRA r: Shift right arithmetic (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
SRA (HL): Shift right arithmetic (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
SWAP r: Swap nibbles (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
SWAP (HL): Swap nibbles (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
SRL r: Shift right logical (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
SRL (HL): Shift right logical (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
BIT b, r: Test bit (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
BIT b, (HL): Test bit (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
RES b, r: Reset bit (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
RES b, (HL): Reset bit (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
SET b, r: Set bit (register) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
SET b, (HL): Set bit (indirect HL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
6.7 Control flow instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
JP nn: Jump . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
JP HL: Jump to HL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
JP cc, nn: Jump (conditional) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
JR e: Relative jump . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
JR cc, e: Relative jump (conditional) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
CALL nn: Call function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
CALL cc, nn: Call function (conditional) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
RET: Return from function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
RET cc: Return from function (conditional) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
RETI: Return from interrupt handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
RST n: Restart / Call function (implied) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
6.8 Miscellaneous instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
HALT: Halt system clock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
STOP: Stop system and main clocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
DI: Disable interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
EI: Enable interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
NOP: No operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
7
Early DMG boot ROM (“DMG0”) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
8 DMA (Direct Memory Access) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
8.1 Object Attribute Memory (OAM) DMA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
OAM DMA address decoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
OAM DMA transfer timing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
OAM DMA bus conflicts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
9 PPU (Picture Processing Unit) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
10 Port P1 (Joypad, Super Game Boy communication) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
11 Serial communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Appendices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
8
9
Part I
10
Chapter 1
Introduction
The original Game Boy and its successors were the most popular and financially successful
handheld consoles in the 1990s and early 2000s with several millions units sold and a large cat-
alogue of officially published games. Unlike many older consoles, Game Boys use only a single
integrated System-on-a-Chip (SoC) for almost everything, and this SoC includes the processor
(CPU) core, some memories, and various peripherals.
Caveat
The Game Boy SoC is sometimes called the “CPU”, even though it has a large amount of
other peripherals as well. For example, the Game Boy Pocket SoC literally has the text
“CPU MGB” on it, even though the CPU core takes only a small fraction of the entire chip
area. This terminology is therefore misleading, and is like calling a computer mother-
board and all connected expansion cards and storage devices the “CPU”.
This document always makes a clear distiction between the entire chip (SoC) and the
processor inside it (the CPU core).
Most Game Boy consoles are handhelds, starting from the original Game Boy in 1989, ending
with the Game Boy Micro in 2005. In addition to handheld devices, Game Boy SoCs are also
used in some accessories meant for other consoles, such as the Super Game Boy for the SNES/
SFC.
Game Boy consoles and their SoCs can be categorized based on three supported technical ar-
chitectures:
• GB: the original Game Boy architecture with a Sharp SM83 CPU core and 4-level grayscale
graphics
• GBC: a mostly backwards compatible extension to the GB architecture that adds color graph-
ics and small improvements
• GBA: a completely different architecture based on the ARM processor instruction set and a
completely redesigned set of peripherals. This document does not cover GBA architecture,
because it has little in common with GB/GBC. GBA-based consoles and chips are only men-
tioned for their backwards compatibility with GB/GBC architectures.
Table 1.1 lists all officially released Game Boy consoles, including handhelds and accessories
for other consoles. Every model has an internal codename, such as original Game Boy’s code-
name Dot Matrix Game (DMG), that is also present on the mainboard.
11
Caveat
This document refers to different console models usually by their unique codename to
prevent confusion. For example, using the abbreviation GBP could refer to either Game
Boy Pocket or Game Boy Player, but there’s no confusion when MGB and GBS are used
instead.
In this document GBC refers to the technical architecture, while CGB refers to Game Boy
Color consoles specifically. Likewise, GBA refers to the architecture and AGB to exactly
one console model.
12
Chapter 2
Clocks
13
In addition to the system clock and other clocks derived from it, Game Boy systems also use
inverted clocks in some peripherals, which means the rising edge of an inverted clock may hap-
pen at the same time as a falling edge of the original clock. Figure 2.1 shows two clock periods
of the system clock and an inverted clock derived from it, and how they are out of phase due
to clock inversion.
period period
CLK 4 MiHz
Inverted 4 MiHz
also also
a period a period
Figure 2.1: Example clock periods
T1R T1F T2R T2F T3R T3F T4R T4F
CLK 4 MiHz T1 T1 T2 T2 T3 T3 T4 T4
PHI 1 MiHz
Figure 2.2: Clock edges in a machine cycle
14
Part II
15
Chapter 3
Introduction
The CPU core in the Game Boy SoC is a custom Sharp design that hasn’t publicly been given
a name by either Sharp or Nintendo. However, using old Sharp datasheets and databooks as
evidence, the core has been identified to be a Sharp SM83 CPU core, or at least something
that is 100% compatible with it. SM83 is a custom CPU core used in some custom Application
Specific Integrated Chips (ASICs) manufactured by Sharp in the 1980s and 1990s.
Warning
Some sources claim Game Boy uses a “modified” Zilog Z80 or Intel 8080 CPU core.
While the SM83 resembles both and has many identical instructions, it can’t execute all
Z80/8080 programs, and finer details such as timing of instructions often differ.
SM83 is an 8-bit CPU core with a 16-bit address bus. The Instruction Set Architecture (ISA) is
based on both Z80 and 8080, and is close enough to Z80 that programmers familiar with Z80
assembly can quickly become productive with SM83 as well. Some Z80 programs may also work
directly on SM83, assuming only opcodes supported by both are used and the program is not
sensitive to timing differences.
🧩 Speculation
Sharp most likely designed SM83 to closely resemble Z80, so it would be easy for pro-
grammers already familiar with the widely popular Z80 to write programs for it. However,
SM83 is not a “modified Z80” because the internal implementation is completely differ-
ent. At the time Sharp also manufactured real Z80 chips such as LH0080 under a license
from Zilog, so they were familiar with Z80 internals but did not directly copy the actual
implementation of the CPU core. If you compare photos of a decapped Z80 chip and a
GB SoC, you will see two very different-looking CPU cores.
3.1 History
The first known mention of the SM83 CPU core is in Sharp Microcomputers Data Book (1990),
where it is listed as the CPU core used in the SM8320 8-bit microcomputer chip, intended for
inverter air conditioners [1]. The data book describes some details of the CPU core, such as a
high-level overview of the supported instructions, but precise details such as full opcode tables
are not included. Another CPU core called SM82 is also mentioned, but based on the details it’s
clearly a completely different one.
The SM83 CPU core later appeared in Sharp Microcomputer Data Book (1996), where it is listed
as the CPU core in the SM8311/SM8313/SM8314/SM8315 8-bit microcomputer chips, meant for
home appliances [2]. This data book describes the CPU core in much more detailed manner,
and other than some mistakes in the descriptions, the details seem to match what is known
about the GB SoC CPU core from other sources.
16
Chapter 4
Simple model
17
Chapter 5
Warning
Sharp SM831x is a family of single-chip SoCs from Sharp that use the SM83 CPU core,
and their datasheet [3] includes a description of fetch/execute overlap. However, the de-
scription is not completely correct and can in fact be misleading.
For example, the timing diagram includes an instruction that does not involve opcode
fetch at all, and memory operations for two instructions are shown to happen at the
same time, which is not possible.
0x1000 INC A
0x1001 LDH (n), A
0x1003 RST 0x08
0x0008 NOP
The following timing diagram shows all memory operations done by the CPU, and the fetch
and execute stages of each instruction:
18
CLK 4 MiHz
PHI 1 MiHz
Mem R/W R: opcode R: opcode R: n W: A R: opcode W: msb(PC) W: lsb(PC) R: opcode R: opcode
Mem addr 0x1000 0x1001 0x1002 0xFF00+n 0x1003 SP-1 SP-2 0x0008 0x0009
19
Chapter 6
6.1 Overview
CB opcode prefix
Undefined opcodes
20
6.2 8-bit load instructions
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x41: # example: LD B, C
B = C
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2/M1
if IR == 0x41: # example: LD B, C
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; B = C
21
LD r, n: Load register (immediate)
Load to the 8-bit register r, the immediate data n.
Opcode 0b00xxx110/various Duration 2 machine cycles
Length 2 bytes: opcode + n Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x06: # example: LD B, n
B = read_memory(addr=PC); PC = PC + 1
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0x06: # example: LD B, n
Z = read_memory(addr=PC); PC = PC + 1
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; B = Z
22
LD r, (HL): Load register (indirect HL)
Load to the 8-bit register r, data from the absolute address specified by the 16-bit register HL.
Opcode 0b01xxx110/various Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x46: # example: LD B, (HL)
B = read_memory(addr=HL)
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0x46: # example: LD B, (HL)
Z = read_memory(addr=HL)
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; B = Z
23
LD (HL), r: Load from register (indirect HL)
Load to the absolute address specified by the 16-bit register HL, data from the 8-bit register r.
Opcode 0b01110xxx/various Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x70: # example: LD (HL), B
write_memory(addr=HL, data=B)
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0x70: # example: LD (HL), B
write_memory(addr=HL, data=B)
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
24
LD (HL), n: Load from immediate data (indirect HL)
Load to the absolute address specified by the 16-bit register HL, the immediate data n.
Opcode 0b00110110/0x36 Duration 3 machine cycles
Length 2 bytes: opcode + n Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x36:
n = read_memory(addr=PC); PC = PC + 1
write_memory(addr=HL, data=n)
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0x36:
Z = read_memory(addr=PC); PC = PC + 1
# M3
write_memory(addr=HL, data=Z)
# M4/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
25
LD A, (BC): Load accumulator (indirect BC)
Load to the 8-bit A register, data from the absolute address specified by the 16-bit register BC.
Opcode 0b00001010/0x0A Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x0A:
A = read_memory(addr=BC)
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0x0A:
Z = read_memory(addr=BC)
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z
26
LD A, (DE): Load accumulator (indirect DE)
Load to the 8-bit A register, data from the absolute address specified by the 16-bit register DE.
Opcode 0b00011010/0x1A Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x1A:
A = read_memory(addr=DE)
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0x1A:
Z = read_memory(addr=DE)
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z
27
LD (BC), A: Load from accumulator (indirect BC)
Load to the absolute address specified by the 16-bit register BC, data from the 8-bit A register.
Opcode 0b00000010/0x02 Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x02:
write_memory(addr=BC, data=A)
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0x02:
write_memory(addr=BC, data=A)
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
28
LD (DE), A: Load from accumulator (indirect DE)
Load to the absolute address specified by the 16-bit register DE, data from the 8-bit A register.
Opcode 0b00010010/0x12 Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x12:
write_memory(addr=DE, data=A)
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0x12:
write_memory(addr=DE, data=A)
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
29
LD A, (nn): Load accumulator (direct)
Load to the 8-bit A register, data from the absolute address specified by the 16-bit operand nn.
Opcode 0b11111010/0xFA Duration 4 machine cycles
Length 3 bytes: opcode + LSB(nn) + MSB(nn) Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xFA:
nn_lsb = read_memory(addr=PC); PC = PC + 1
nn_msb = read_memory(addr=PC); PC = PC + 1
nn = unsigned_16(lsb=nn_lsb, msb=nn_msb)
A = read_memory(addr=nn)
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0xFA:
Z = read_memory(addr=PC); PC = PC + 1
# M3
W = read_memory(addr=PC); PC = PC + 1
# M4
Z = read_memory(addr=WZ)
# M5/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z
30
LD (nn), A: Load from accumulator (direct)
Load to the absolute address specified by the 16-bit operand nn, data from the 8-bit A register.
Opcode 0b11101010/0xEA Duration 4 machine cycles
Length 3 bytes: opcode + LSB(nn) + MSB(nn) Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xEA:
nn_lsb = read_memory(addr=PC); PC = PC + 1
nn_msb = read_memory(addr=PC); PC = PC + 1
nn = unsigned_16(lsb=nn_lsb, msb=nn_msb)
write_memory(addr=nn, data=A)
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1 PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0xEA:
Z = read_memory(addr=PC); PC = PC + 1
# M3
W = read_memory(addr=PC); PC = PC + 1
# M4
write_memory(addr=WZ, data=A)
# M5/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
31
LDH A, (C): Load accumulator (indirect 0xFF00+C)
Load to the 8-bit A register, data from the address specified by the 8-bit C register. The full 16-bit
absolute address is obtained by setting the most significant byte to 0xFF and the least signifi-
cant byte to the value of C, so the possible range is 0xFF00-0xFFFF.
Opcode 0b11110010/0xF2 Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xF2:
A = read_memory(addr=unsigned_16(lsb=C, msb=0xFF))
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0xF2:
Z = read_memory(addr=unsigned_16(lsb=C, msb=0xFF))
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z
32
LDH (C), A: Load from accumulator (indirect 0xFF00+C)
Load to the address specified by the 8-bit C register, data from the 8-bit A register. The full 16-bit
absolute address is obtained by setting the most significant byte to 0xFF and the least signifi-
cant byte to the value of C, so the possible range is 0xFF00-0xFFFF.
Opcode 0b11100010/0xE2 Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xE2:
write_memory(addr=unsigned_16(lsb=C, data=msb=0xFF), data=A)
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0xE2:
write_memory(addr=unsigned_16(lsb=C, data=msb=0xFF), data=A)
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
33
LDH A, (n): Load accumulator (direct 0xFF00+n)
Load to the 8-bit A register, data from the address specified by the 8-bit immediate data n. The
full 16-bit absolute address is obtained by setting the most significant byte to 0xFF and the
least significant byte to the value of n, so the possible range is 0xFF00-0xFFFF.
Opcode 0b11110000/0xF0 Duration 3 machine cycles
Length 2 bytes: opcode + n Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xF0:
n = read_memory(addr=PC); PC = PC + 1
A = read_memory(addr=unsigned_16(lsb=n, msb=0xFF))
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0xF0:
Z = read_memory(addr=PC); PC = PC + 1
# M3
Z = read_memory(addr=unsigned_16(lsb=Z, msb=0xFF))
# M4/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z
34
LDH (n), A: Load from accumulator (direct 0xFF00+n)
Load to the address specified by the 8-bit immediate data n, data from the 8-bit A register. The
full 16-bit absolute address is obtained by setting the most significant byte to 0xFF and the
least significant byte to the value of n, so the possible range is 0xFF00-0xFFFF.
Opcode 0b11100000/0xE0 Duration 3 machine cycles
Length 2 bytes: opcode + n Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xE0:
n = read_memory(addr=PC); PC = PC + 1
write_memory(addr=unsigned_16(lsb=n, msb=0xFF), data=A)
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0xE0:
Z = read_memory(addr=PC); PC = PC + 1
# M3
write_memory(addr=unsigned_16(lsb=Z, msb=0xFF), data=A)
# M4/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
35
LD A, (HL-): Load accumulator (indirect HL, decrement)
Load to the 8-bit A register, data from the absolute address specified by the 16-bit register HL.
The value of HL is decremented after the memory read.
Opcode 0b00111010/0x3A Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x3A:
A = read_memory(addr=HL); HL = HL - 1
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous HL ← HL - 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0x3A:
Z = read_memory(addr=HL); HL = HL - 1
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z
36
LD (HL-), A: Load from accumulator (indirect HL, decrement)
Load to the absolute address specified by the 16-bit register HL, data from the 8-bit A register.
The value of HL is decremented after the memory write.
Opcode 0b00110010/0x32 Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x32:
write_memory(addr=HL, data=A); HL = HL - 1
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous HL ← HL - 1 PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0x32:
write_memory(addr=HL, data=A); HL = HL - 1
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
37
LD A, (HL+): Load accumulator (indirect HL, increment)
Load to the 8-bit A register, data from the absolute address specified by the 16-bit register HL.
The value of HL is incremented after the memory read.
Opcode 0b00101010/0x2A Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x2A:
A = read_memory(addr=HL); HL = HL + 1
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous HL ← HL + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0x2A:
Z = read_memory(addr=HL); HL = HL + 1
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; A = Z
38
LD (HL+), A: Load from accumulator (indirect HL, increment)
Load to the absolute address specified by the 16-bit register HL, data from the 8-bit A register.
The value of HL is decremented after the memory write.
Opcode 0b00100010/0x22 Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x22:
write_memory(addr=HL, data=A); HL = HL + 1
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous HL ← HL + 1 PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0x22:
write_memory(addr=HL, data=A); HL = HL + 1
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
39
6.3 16-bit load instructions
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x01: # example: LD BC, nn
nn_lsb = read_memory(addr=PC); PC = PC + 1
nn_msb = read_memory(addr=PC); PC = PC + 1
nn = unsigned_16(lsb=nn_lsb, msb=nn_msb)
BC = nn
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1 PC ← PC + 1
ALU op Previous
Misc op Previous rr ← WZ
# M2
if IR == 0x01: # example: LD BC, nn
Z = read_memory(addr=PC); PC = PC + 1
# M3
W = read_memory(addr=PC); PC = PC + 1
# M4/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; BC = WZ
40
LD (nn), SP: Load from stack pointer (direct)
Load to the absolute address specified by the 16-bit operand nn, data from the 16-bit SP reg-
ister.
Opcode 0b00001000/0x08 Duration 5 machine cycles
Length 3 bytes: opcode + LSB(nn) + MSB(nn) Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4 M5
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x08:
nn_lsb = read_memory(addr=PC); PC = PC + 1
nn_msb = read_memory(addr=PC); PC = PC + 1
nn = unsigned_16(lsb=nn_lsb, msb=nn_msb)
write_memory(addr=nn, data=lsb(SP)); nn = nn + 1
write_memory(addr=nn, data=msb(SP))
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5 M6/M1
Data bus IR ← mem Z ← mem W ← mem mem ← SPL mem ← SPH IR ← mem
IDU op Previous PC ← PC + 1 PC ← PC + 1 WZ ← WZ + 1 PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0x08:
Z = read_memory(addr=PC); PC = PC + 1
# M3
W = read_memory(addr=PC); PC = PC + 1
# M4
write_memory(addr=WZ, data=lsb(SP)); WZ = WZ + 1
# M5
write_memory(addr=WZ, data=msb(SP))
# M6/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
41
LD SP, HL: Load stack pointer from HL
Load to the 16-bit SP register, data from the 16-bit HL register.
Opcode 0b11111001/0xF9 Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xF9:
SP = HL
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous SP ← HL PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0xF9:
SP = HL
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
42
PUSH rr: Push to stack
Push to the stack memory, data from the 16-bit register rr.
Opcode 0b11xx0101/various Duration 4 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xC5: # example: PUSH BC
SP = SP - 1
write_memory(addr=SP, data=msb(BC)); SP = SP - 1
write_memory(addr=SP, data=lsb(BC))
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5/M1
IDU op Previous SP ← SP - 1 SP ← SP - 1 SP ← SP PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0xC5: # example: PUSH BC
SP = SP - 1
# M3
write_memory(addr=SP, data=msb(BC)); SP = SP - 1
# M4
write_memory(addr=SP, data=lsb(BC))
# M5/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
43
POP rr: Pop from stack
Pops to the 16-bit register rr, data from the stack memory.
This instruction does not do calculations that affect flags, but POP AF completely replaces the
F register value, so all flags are changed based on the 8-bit data that is read from memory.
Opcode 0b11xx0001/various Duration 3 machine cycles
Length 1 byte: opcode Flags See the instruction description
Simple timing and pseudocode
M-cycle M1 M2 M3
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xC1: # example: POP BC
lsb = read_memory(addr=SP); SP = SP + 1
msb = read_memory(addr=SP); SP = SP + 1
BC = unsigned_16(lsb=lsb, msb=msb)
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
IDU op Previous SP ← SP + 1 SP ← SP + 1 PC ← PC + 1
ALU op Previous
Misc op Previous rr ← WZ
# M2
if IR == 0xC1: # example: POP BC
Z = read_memory(addr=SP); SP = SP + 1
# M3
W = read_memory(addr=SP); SP = SP + 1
# M4/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; BC = WZ
44
LD HL, SP+e: Load HL from adjusted stack pointer
Load to the HL register, 16-bit data calculated by adding the signed 8-bit operand e to the 16-
bit value of the SP register.
Opcode 0b11111000/0xF8 Duration 3 machine cycles
Length 2 bytes: opcode + e Flags Z = 0, N = 0, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xF8:
e = signed_8(read_memory(addr=PC)); PC = PC + 1
result, carry_per_bit = SP + e
HL = result
flags.Z = 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0xF8:
Z = read_memory(addr=PC); PC = PC + 1
# M3
result, carry_per_bit = lsb(SP) + Z
L = result
flags.Z = 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Z_sign = bit(7, Z)
# M4/M1
adj = 0xFF if Z_sign else 0x00
result = msb(SP) + adj + flags.C
H = result
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
45
6.4 8-bit arithmetic and logical instructions
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x80: # example: ADD B
result, carry_per_bit = A + B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2/M1
if IR == 0x80: # example: ADD B
result, carry_per_bit = A + B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
46
ADD (HL): Add (indirect HL)
Adds to the 8-bit A register, data from the absolute address specified by the 16-bit register HL,
and stores the result back into the A register.
Opcode 0b10000110/0x86 Duration 2 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x86:
data = read_memory(addr=HL)
result, carry_per_bit = A + data
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0x86:
Z = read_memory(addr=HL)
# M3/M1
result, carry_per_bit = A + Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
47
ADD n: Add (immediate)
Adds to the 8-bit A register, the immediate data n, and stores the result back into the A register.
Opcode 0b11000110/0xC6 Duration 2 machine cycles
Length 2 bytes: opcode + n Flags Z = ⭐, N = 0, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xC6:
n = read_memory(addr=PC); PC = PC + 1
result, carry_per_bit = A + n
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0xC6:
Z = read_memory(addr=PC); PC = PC + 1
# M3/M1
result, carry_per_bit = A + Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
48
ADC r: Add with carry (register)
Adds to the 8-bit A register, the carry flag and the 8-bit register r, and stores the result back
into the A register.
Opcode 0b10001xxx/various Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x88: # example: ADC B
result, carry_per_bit = A + B + flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
ALU op Previous A ← A +c r
Misc op Previous
# M2/M1
if IR == 0x88: # example: ADC B
result, carry_per_bit = A + B + flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
49
ADC (HL): Add with carry (indirect HL)
Adds to the 8-bit A register, the carry flag and data from the absolute address specified by the
16-bit register HL, and stores the result back into the A register.
Opcode 0b10001110/0x8E Duration 2 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x8E:
data = read_memory(addr=HL)
result, carry_per_bit = A + data + flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
ALU op Previous A ← A +c Z
Misc op Previous
# M2
if IR == 0x8E:
Z = read_memory(addr=HL)
# M3/M1
result, carry_per_bit = A + Z + flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
50
ADC n: Add with carry (immediate)
Adds to the 8-bit A register, the carry flag and the immediate data n, and stores the result back
into the A register.
Opcode 0b11001110/0xCE Duration 2 machine cycles
Length 2 bytes: opcode + n Flags Z = ⭐, N = 0, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xCE:
n = read_memory(addr=PC); PC = PC + 1
result, carry_per_bit = A + n + flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
ALU op Previous A ← A +c Z
Misc op Previous
# M2
if IR == 0xCE:
Z = read_memory(addr=PC); PC = PC + 1
# M3/M1
result, carry_per_bit = A + Z + flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
51
SUB r: Subtract (register)
Subtracts from the 8-bit A register, the 8-bit register r, and stores the result back into the A
register.
Opcode 0b10010xxx/various Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, N = 1, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x90: # example: SUB B
result, carry_per_bit = A - B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2/M1
if IR == 0x90: # example: SUB B
result, carry_per_bit = A - B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
52
SUB (HL): Subtract (indirect HL)
Subtracts from the 8-bit A register, data from the absolute address specified by the 16-bit reg-
ister HL, and stores the result back into the A register.
Opcode 0b10010110/0x96 Duration 2 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 1, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x96:
data = read_memory(addr=HL)
result, carry_per_bit = A - data
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0x96:
Z = read_memory(addr=HL)
# M3/M1
result, carry_per_bit = A - Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
53
SUB n: Subtract (immediate)
Subtracts from the 8-bit A register, the immediate data n, and stores the result back into the A
register.
Opcode 0b11010110/0xD6 Duration 2 machine cycles
Length 2 bytes: opcode + n Flags Z = ⭐, N = 1, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xD6:
n = read_memory(addr=PC); PC = PC + 1
result, carry_per_bit = A - n
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0xD6:
Z = read_memory(addr=PC); PC = PC + 1
# M3/M1
result, carry_per_bit = A - Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
54
SBC r: Subtract with carry (register)
Subtracts from the 8-bit A register, the carry flag and the 8-bit register r, and stores the result
back into the A register.
Opcode 0b10011xxx/various Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, N = 1, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x98: # example: SBC B
result, carry_per_bit = A - B - flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
ALU op Previous A ← A -c r
Misc op Previous
# M2/M1
if IR == 0x98: # example: SBC B
result, carry_per_bit = A - B - flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
55
SBC (HL): Subtract with carry (indirect HL)
Subtracts from the 8-bit A register, the carry flag and data from the absolute address specified
by the 16-bit register HL, and stores the result back into the A register.
Opcode 0b10011110/0x9E Duration 2 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 1, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x9E:
data = read_memory(addr=HL)
result, carry_per_bit = A - data - flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
ALU op Previous A ← A -c Z
Misc op Previous
# M2
if IR == 0x9E:
Z = read_memory(addr=HL)
# M3/M1
result, carry_per_bit = A - Z - flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
56
SBC n: Subtract with carry (immediate)
Subtracts from the 8-bit A register, the carry flag and the immediate data n, and stores the re-
sult back into the A register.
Opcode 0b11011110/0xDE Duration 2 machine cycles
Length 2 bytes: opcode + n Flags Z = ⭐, N = 1, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xDE:
n = read_memory(addr=PC); PC = PC + 1
result, carry_per_bit = A - n - flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
ALU op Previous A ← A -c Z
Misc op Previous
# M2
if IR == 0xDE:
Z = read_memory(addr=PC); PC = PC + 1
# M3/M1
result, carry_per_bit = A - Z - flags.C
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
57
CP r: Compare (register)
Subtracts from the 8-bit A register, the 8-bit register r, and updates flags based on the result.
This instruction is basically identical to SUB r, but does not update the A register.
Opcode 0b10111xxx/various Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, N = 1, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xB8: # example: CP B
result, carry_per_bit = A - B
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2/M1
if IR == 0xB8: # example: CP B
result, carry_per_bit = A - B
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
58
CP (HL): Compare (indirect HL)
Subtracts from the 8-bit A register, data from the absolute address specified by the 16-bit reg-
ister HL, and updates flags based on the result. This instruction is basically identical to SUB
(HL), but does not update the A register.
Opcode 0b10011110/0x9E Duration 2 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 1, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xBE:
data = read_memory(addr=HL)
result, carry_per_bit = A - data
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0xBE:
Z = read_memory(addr=HL)
# M3/M1
result, carry_per_bit = A - Z
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
59
CP n: Compare (immediate)
Subtracts from the 8-bit A register, the immediate data n, and updates flags based on the result.
This instruction is basically identical to SUB n, but does not update the A register.
Opcode 0b11111110/0xFE Duration 2 machine cycles
Length 2 bytes: opcode + n Flags Z = ⭐, N = 1, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xFE:
n = read_memory(addr=PC); PC = PC + 1
result, carry_per_bit = A - n
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0xFE:
Z = read_memory(addr=PC); PC = PC + 1
# M3/M1
result, carry_per_bit = A - Z
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
60
INC r: Increment (register)
Increments data in the 8-bit register r.
Opcode 0b00xxx100/various Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = ⭐
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x04: # example: INC B
result, carry_per_bit = B + 1
B = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
61
INC (HL): Increment (indirect HL)
Increments data at the absolute address specified by the 16-bit register HL.
Opcode 0b00110100/0x34 Duration 3 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x34:
data = read_memory(addr=HL)
result, carry_per_bit = data + 1
write_memory(addr=HL, data=result)
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0x34:
Z = read_memory(addr=HL)
# M3
result, carry_per_bit = Z + 1
write_memory(addr=HL, data=result)
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
# M4/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
62
DEC r: Decrement (register)
Increments data in the 8-bit register r.
Opcode 0b00xxx101/various Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, N = 1, H = ⭐
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
# example: DEC B
if opcode == 0x05:
result, carry_per_bit = B - 1
B = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2/M1
if IR == 0x05: # example: DEC B
result, carry_per_bit = B - 1
B = result
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
63
DEC (HL): Decrement (indirect HL)
Decrements data at the absolute address specified by the 16-bit register HL.
Opcode 0b00110101/0x35 Duration 3 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 1, H = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x35:
data = read_memory(addr=HL)
result, carry_per_bit = data - 1
write_memory(addr=HL, data=result)
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0x35:
Z = read_memory(addr=HL)
# M3
result, carry_per_bit = Z - 1
write_memory(addr=HL, data=result)
flags.Z = 1 if result == 0 else 0
flags.N = 1
flags.H = 1 if carry_per_bit[3] else 0
# M4/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
64
AND r: Bitwise AND (register)
Performs a bitwise AND operation between the 8-bit A register and the 8-bit register r, and
stores the result back into the A register.
Opcode 0b10100xxx/various Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = 1, C = 0
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xA0: # example: AND B
result = A & B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1
flags.C = 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2/M1
if IR == 0xA0: # example: AND B
result = A & B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1
flags.C = 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
65
AND (HL): Bitwise AND (indirect HL)
Performs a bitwise AND operation between the 8-bit A register and data from the absolute
address specified by the 16-bit register HL, and stores the result back into the A register.
Opcode 0b10100110/0xA6 Duration 2 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = 1, C = 0
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xA6:
data = read_memory(addr=HL)
result = A & data
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1
flags.C = 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0xA6:
Z = read_memory(addr=HL)
# M3/M1
result = A & Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1
flags.C = 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
66
AND n: Bitwise AND (immediate)
Performs a bitwise AND operation between the 8-bit A register and immediate data n, and
stores the result back into the A register.
Opcode 0b11100110/0xE6 Duration 2 machine cycles
Length 2 bytes: opcode + n Flags Z = ⭐, N = 0, H = 1, C = 0
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xE6:
n = read_memory(addr=PC); PC = PC + 1
result = A & n
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1
flags.C = 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0xE6:
Z = read_memory(addr=PC); PC = PC + 1
# M3/M1
result = A & Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 1
flags.C = 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
67
OR r: Bitwise OR (register)
Performs a bitwise OR operation between the 8-bit A register and the 8-bit register r, and stores
the result back into the A register.
Opcode 0b10110xxx/various Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = 0, C = 0
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xB0: # example: OR B
result = A | B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
ALU op Previous A ← A or r
Misc op Previous
# M2/M1
if IR == 0xB0: # example: OR B
result = A | B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
68
OR (HL): Bitwise OR (indirect HL)
Performs a bitwise OR operation between the 8-bit A register and data from the absolute ad-
dress specified by the 16-bit register HL, and stores the result back into the A register.
Opcode 0b10110110/0xB6 Duration 2 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = 0, C = 0
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xB6:
data = read_memory(addr=HL)
result = A | data
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
ALU op Previous A ← A or Z
Misc op Previous
# M2
if IR == 0xB6:
Z = read_memory(addr=HL)
# M3/M1
result = A | Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
69
OR n: Bitwise OR (immediate)
Performs a bitwise OR operation between the 8-bit A register and immediate data n, and stores
the result back into the A register.
Opcode 0b11110110/0xF6 Duration 2 machine cycles
Length 2 bytes: opcode + n Flags Z = ⭐, N = 0, H = 0, C = 0
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xF6:
n = read_memory(addr=PC); PC = PC + 1
result = A | n
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
ALU op Previous A ← A or Z
Misc op Previous
# M2
if IR == 0xF6:
Z = read_memory(addr=PC); PC = PC + 1
# M3/M1
result = A | Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
70
XOR r: Bitwise XOR (register)
Performs a bitwise XOR operation between the 8-bit A register and the 8-bit register r, and
stores the result back into the A register.
Opcode 0b10101xxx/various Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = 0, C = 0
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xA8: # example: XOR B
result = A ^ B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xA8: # example: XOR B
# M2/M1
result = A ^ B
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
71
XOR (HL): Bitwise XOR (indirect HL)
Performs a bitwise XOR operation between the 8-bit A register and data from the absolute ad-
dress specified by the 16-bit register HL, and stores the result back into the A register.
Opcode 0b10101110/0xAE Duration 2 machine cycles
Length 1 byte: opcode Flags Z = ⭐, N = 0, H = 0, C = 0
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xAE:
data = read_memory(addr=HL)
result = A ^ data
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0xAE:
Z = read_memory(addr=HL)
# M3/M1
result = A ^ Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
72
XOR n: Bitwise XOR (immediate)
Performs a bitwise XOR operation between the 8-bit A register and immediate data n, and
stores the result back into the A register.
Opcode 0b11101110/0xEE Duration 2 machine cycles
Length 2 bytes: opcode + n Flags Z = ⭐, N = 0, H = 0, C = 0
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xEE:
n = read_memory(addr=PC); PC = PC + 1
result = A ^ n
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
# M2
if IR == 0xEE:
Z = read_memory(addr=PC); PC = PC + 1
# M3/M1
result = A ^ Z
A = result
flags.Z = 1 if result == 0 else 0
flags.N = 0
flags.H = 0
flags.C = 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
73
CCF: Complement carry flag
Flips the carry flag, and clears the N and H flags.
Opcode 0b00111111/0x3F Duration 1 machine cycle
Length 1 byte: opcode Flags N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x3F:
flags.N = 0
flags.H = 0
flags.C = ~flags.C
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2/M1
if IR == 0x3F:
flags.N = 0
flags.H = 0
flags.C = ~flags.C
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
74
SCF: Set carry flag
Sets the carry flag, and clears the N and H flags.
Opcode 0b00110111/0x37 Duration 1 machine cycle
Length 1 byte: opcode Flags N = 0, H = 0, C = 1
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x37:
flags.N = 0
flags.H = 0
flags.C = 1
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
ALU op Previous cf ← 1
Misc op Previous
# M2/M1
if IR == 0x37:
flags.N = 0
flags.H = 0
flags.C = 1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
75
DAA: Decimal adjust accumulator
TODO
Opcode 0b00100111/0x27 Duration 1 machine cycle
Length 1 byte: opcode Flags Z = ⭐, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1
IDU op Previous PC ← PC + 1
Misc op Previous
TODO
76
CPL: Complement accumulator
Flips all the bits in the 8-bit A register, and sets the N and H flags.
Opcode 0b00101111/0x2F Duration 1 machine cycle
Length 1 byte: opcode Flags N = 1, H = 1
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x2F:
A = ~A
flags.N = 1
flags.H = 1
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2/M1
if IR == 0x2F:
A = ~A
flags.N = 1
flags.H = 1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
77
6.5 16-bit arithmetic instructions
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x03: # example: INC BC
BC = BC + 1
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous rr ← rr + 1 PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0x03: # example: INC BC
BC = BC + 1
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
78
DEC rr: Decrement 16-bit register
Decrements data in the 16-bit register rr.
Opcode 0b00xx1011/various Duration 2 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x0B: # example: DEC BC
BC = BC - 1
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous rr ← rr - 1 PC ← PC + 1
ALU op Previous
Misc op Previous
# M2
if IR == 0x0B: # example: DEC BC
BC = BC - 1
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
79
ADD HL, rr: Add (16-bit register)
Adds to the 16-bit HL register pair, the 16-bit register rr, and stores the result back into the HL
register pair.
Opcode 0b00xx1001/various Duration 2 machine cycles
Length 1 byte: opcode Flags N = 0, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x09: # example: ADD HL, BC
result, carry_per_bit = HL + BC
HL = result
flags.N = 0
flags.H = 1 if carry_per_bit[11] else 0
flags.C = 1 if carry_per_bit[15] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3/M1
IDU op Previous PC ← PC + 1
Misc op Previous
# M2
if IR == 0x09: # example: ADD HL, BC
result, carry_per_bit = L + C
L = result
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
# M3/M1
result, carry_per_bit = H + B + flags.C
H = result
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
80
ADD SP, e: Add to stack pointer (relative)
Loads to the 16-bit SP register, 16-bit data calculated by adding the signed 8-bit operand e to
the 16-bit value of the SP register.
Opcode 0b11101000/0xE8 Duration 4 machine cycles
Length 2 bytes: opcode + e Flags Z = 0, N = 0, H = ⭐, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xE8:
e = signed_8(read_memory(addr=PC)); PC = PC + 1
result, carry_per_bit = SP + e
SP = result
flags.Z = 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous SP ← WZ
# M2
if IR == 0xE8:
Z = read_memory(addr=PC); PC = PC + 1
# M3
result, carry_per_bit = lsb(SP) + Z
Z = result
flags.Z = 0
flags.N = 0
flags.H = 1 if carry_per_bit[3] else 0
flags.C = 1 if carry_per_bit[7] else 0
# M4
result = msb(SP) + adj + flags.C
W = result
# M5/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; SP = WZ
81
82
6.6 Rotate, shift, and bit operation instructions
IDU op Previous PC ← PC + 1
Misc op Previous
TODO
83
RRCA: Rotate right circular (accumulator)
TODO
Opcode 0b00001111/0x0F Duration 1 machine cycle
Length 1 byte: opcode Flags Z = 0, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1
IDU op Previous PC ← PC + 1
Misc op Previous
TODO
84
RLA: Rotate left (accumulator)
TODO
Opcode 0b00010111/0x17 Duration 1 machine cycle
Length 1 byte: opcode Flags Z = 0, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1
IDU op Previous PC ← PC + 1
ALU op Previous A ← rl A
Misc op Previous
TODO
85
RRA: Rotate right (accumulator)
TODO
Opcode 0b00011111/0x1F Duration 1 machine cycle
Length 1 byte: opcode Flags Z = 0, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1
IDU op Previous PC ← PC + 1
ALU op Previous A ← rr A
Misc op Previous
TODO
86
RLC r: Rotate left circular (register)
TODO
Opcode 0b00000xxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
87
RLC (HL): Rotate left circular (indirect HL)
TODO
Opcode 0x06 Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
88
RRC r: Rotate right circular (register)
TODO
Opcode 0b00001xxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
89
RRC (HL): Rotate right circular (indirect HL)
TODO
Opcode 0x0E Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
90
RL r: Rotate left (register)
TODO
Opcode 0b00010xxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
ALU op Previous r ← rl r
Misc op Previous
TODO
91
RL (HL): Rotate left (indirect HL)
TODO
Opcode 0x16 Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
92
RR r: Rotate right (register)
TODO
Opcode 0b00011xxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
ALU op Previous r ← rr r
Misc op Previous
TODO
93
RR (HL): Rotate right (indirect HL)
TODO
Opcode 0x1E Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
94
SLA r: Shift left arithmetic (register)
TODO
Opcode 0b00100xxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
95
SLA (HL): Shift left arithmetic (indirect HL)
TODO
Opcode 0x26 Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
96
SRA r: Shift right arithmetic (register)
TODO
Opcode 0b00101xxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
97
SRA (HL): Shift right arithmetic (indirect HL)
TODO
Opcode 0x2E Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
98
SWAP r: Swap nibbles (register)
TODO
Opcode 0b00110xxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = 0
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
99
SWAP (HL): Swap nibbles (indirect HL)
TODO
Opcode 0x36 Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = 0
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
100
SRL r: Shift right logical (register)
TODO
Opcode 0b00111xxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
101
SRL (HL): Shift right logical (indirect HL)
TODO
Opcode 0x3E Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 0, C = ⭐
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
102
BIT b, r: Test bit (register)
TODO
Opcode 0b01xxxxxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 1
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
103
BIT b, (HL): Test bit (indirect HL)
TODO
Opcode 0b01xxx110/various Duration 3 machine cycles
Length 2 bytes: CB prefix + opcode Flags Z = ⭐, N = 0, H = 1
Simple timing and pseudocode
M-cycle M1 M2 M3
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
104
RES b, r: Reset bit (register)
TODO
Opcode 0b10xxxxxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
105
RES b, (HL): Reset bit (indirect HL)
TODO
Opcode 0b10xxx110/various Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
106
SET b, r: Set bit (register)
TODO
Opcode 0b11xxxxxx/various Duration 2 machine cycles
Length 2 bytes: CB prefix + opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
107
SET b, (HL): Set bit (indirect HL)
TODO
Opcode 0b11xxx110/various Duration 4 machine cycles
Length 2 bytes: CB prefix + opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
IDU op Previous PC ← PC + 1 PC ← PC + 1
Misc op Previous
TODO
108
109
6.7 Control flow instructions
JP nn: Jump
Unconditional jump to the absolute address specified by the 16-bit immediate operand nn.
Opcode 0b11000011/0xC3 Duration 4 machine cycles
Length 3 bytes: opcode + LSB(nn) + MSB(nn) Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xC3:
nn_lsb = read_memory(addr=PC); PC = PC + 1
nn_msb = read_memory(addr=PC); PC = PC + 1
nn = unsigned_16(lsb=nn_lsb, msb=nn_msb)
PC = nn
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5/M1
IDU op Previous PC ← PC + 1 PC ← PC + 1 PC ← PC + 1
ALU op Previous
Misc op Previous PC ← WZ
# M2
if IR == 0xC3:
Z = read_memory(addr=PC); PC = PC + 1
# M3
W = read_memory(addr=PC); PC = PC + 1
# M4
PC = WZ
# M5/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
110
JP HL: Jump to HL
Unconditional jump to the absolute address specified by the 16-bit register HL.
Opcode 0b11101001/0xE9 Duration 1 machine cycle
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xE9:
PC = HL
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← HL + 1
ALU op Previous
Misc op Previous
# M2/M1
if IR == 0xE9:
IR, intr = fetch_cycle(addr=HL); PC = HL + 1
111
Warning
M-cycle M1 M2 M3
cc=false
Mem R/W opcode R: lsb(nn) R: msb(nn)
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xC2: # example: JP NZ, nn
nn_lsb = read_memory(addr=PC); PC = PC + 1
nn_msb = read_memory(addr=PC); PC = PC + 1
nn = unsigned_16(lsb=nn_lsb, msb=nn_msb)
if !flags.Z: # cc=true
PC = nn
112
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5/M1
ALU op Previous
M-cycle M1 M2 M3 M4/M1
ALU op Previous
# M2
if IR == 0xC2: # example: JP NZ, nn
Z = read_memory(addr=PC); PC = PC + 1
# M3
W = read_memory(addr=PC); PC = PC + 1
if !flags.Z: # cc=true
# M4
PC = WZ
# M5/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
else: # cc=false
# M4/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
113
JR e: Relative jump
Unconditional jump to the relative address specified by the signed 8-bit operand e.
Opcode 0b00011000/0x18 Duration 3 machine cycles
Length 2 bytes: opcode + e Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x18:
e = signed_8(read_memory(addr=PC)); PC = PC + 1
PC = PC + e
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
Misc op Previous
# M2
if IR == 0x18:
Z = read_memory(addr=PC); PC = PC + 1
# M3
Z_sign = bit(7, Z)
result, carry_per_bit = Z + lsb(PC)
Z = result
adj = 1 if carry_per_bit[7] and not Z_sign else
-1 if not carry_per_bit[7] and Z_sign else
0
W = msb(PC) + adj
# M4/M1
IR, intr = fetch_cycle(addr=WZ); PC = WZ + 1
114
JR cc, e: Relative jump (conditional)
Conditional jump to the relative address specified by the signed 8-bit operand e, depending on
the condition cc.
Note that the operand (relative address offset) is read even when the condition is false!
Opcode 0b001xx000/various Duration 3 machine cycles (cc=true)
2 machine cycles (cc=false)
Length 2 bytes: opcode + e Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3
cc=true
Mem R/W opcode R: e
M-cycle M1 M2
cc=false
Mem R/W opcode R: e
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x20:
e = signed_8(read_memory(addr=PC)); PC = PC + 1
if !flags.Z: # cc=true
PC = PC + e
115
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4/M1
M-cycle M1 M2 M3/M1
ALU op Previous
# M2
if IR == 0x20:
Z = read_memory(addr=PC); PC = PC + 1
if !flags.Z: # cc=true
# M3
Z_sign = bit(7, Z)
result, carry_per_bit = Z + lsb(PC)
Z = result
adj = 1 if carry_per_bit[7] and not Z_sign else
-1 if not carry_per_bit[7] and Z_sign else
0
W = msb(PC) + adj
# M4/M1
IR, intr = fetch_cycle(addr=WZ); PC = WZ + 1
else: # cc=false
# M3/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
116
CALL nn: Call function
Unconditional function call to the absolute address specified by the 16-bit operand nn.
Opcode 0b11001101/0xCD Duration 6 machine cycles
Length 3 bytes: opcode + LSB(nn) + MSB(nn) Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4 M5 M6
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xCD:
nn_lsb = read_memory(addr=PC); PC = PC + 1
nn_msb = read_memory(addr=PC); PC = PC + 1
nn = unsigned_16(lsb=nn_lsb, msb=nn_msb)
SP = SP - 1
write_memory(addr=SP, data=msb(PC)); SP = SP - 1
write_memory(addr=SP, data=lsb(PC))
PC = nn
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5 M6 M7/M1
Data bus IR ← mem Z ← mem W ← mem mem ← PCH mem ← PCL IR ← mem
IDU op Previous PC ← PC + 1 PC ← PC + 1 SP ← SP - 1 SP ← SP - 1 SP ← SP PC ← PC + 1
ALU op Previous
Misc op Previous PC ← WZ
# M2
if IR == 0xCD:
Z = read_memory(addr=PC); PC = PC + 1
# M3
W = read_memory(addr=PC); PC = PC + 1
# M4
SP = SP - 1
# M5
write_memory(addr=SP, data=msb(PC)); SP = SP - 1
# M6
write_memory(addr=SP, data=lsb(PC)); PC = WZ
# M7/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
117
CALL cc, nn: Call function (conditional)
Conditional function call to the absolute address specified by the 16-bit operand nn, depending
on the condition cc.
Note that the operand (absolute address) is read even when the condition is false!
Opcode 0b110xx100/various Duration 6 machine cycles (cc=true)
3 machine cycles (cc=false)
Length 3 bytes: opcode + LSB(nn) + MSB(nn) Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4 M5 M6
cc=true
Mem R/W opcode R: lsb(nn) R: msb(nn) W: msb(PC₀+3) W: lsb(PC₀+3)
M-cycle M1 M2 M3
cc=false
Mem R/W opcode R: lsb(nn) R: msb(nn)
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xC4: # example: CALL NZ, nn
nn_lsb = read_memory(addr=PC); PC = PC + 1
nn_msb = read_memory(addr=PC); PC = PC + 1
nn = unsigned_16(lsb=nn_lsb, msb=nn_msb)
if !flags.Z: # cc=true
SP = SP - 1
write_memory(addr=SP, data=msb(PC)); SP = SP - 1
write_memory(addr=SP, data=lsb(PC))
PC = nn
118
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5 M6 M7/M1
Data bus IR ← mem Z ← mem W ← mem mem ← PCH mem ← PCL IR ← mem
cc=true
IDU op Previous PC ← PC + 1 PC ← PC + 1 SP ← SP - 1 SP ← SP - 1 SP ← SP PC ← PC + 1
ALU op Previous
M-cycle M1 M2 M3 M4/M1
ALU op Previous
# M2
if IR == 0xC4: # example: CALL NZ, nn
Z = read_memory(addr=PC); PC = PC + 1
# M3
W = read_memory(addr=PC); PC = PC + 1
if !flags.Z: # cc=true
# M4
SP = SP - 1
# M5
write_memory(addr=SP, data=msb(PC)); SP = SP - 1
# M6
write_memory(addr=SP, data=lsb(PC)); PC = WZ
# M7/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
else: # cc=false
# M4/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
119
RET: Return from function
Unconditional return from a function.
Opcode 0b11001001/0xC9 Duration 4 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xC9:
lsb = read_memory(addr=SP); SP = SP + 1
msb = read_memory(addr=SP); SP = SP + 1
PC = unsigned_16(lsb=lsb, msb=msb)
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5/M1
IDU op Previous SP ← SP + 1 SP ← SP + 1 PC ← PC + 1
ALU op Previous
Misc op Previous PC ← WZ
# M2
if IR == 0xC9:
Z = read_memory(addr=SP); SP = SP + 1
# M3
W = read_memory(addr=SP); SP = SP + 1
# M4
PC = WZ
# M5/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
120
RET cc: Return from function (conditional)
Conditional return from a function, depending on the condition cc.
Opcode 0b110xx000/various Duration 5 machine cycles (cc=true)
2 machine cycles (cc=false)
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4 M5
cc=true
Mem R/W opcode R: lsb(PC) R: msb(PC)
M-cycle M1 M2
cc=false
Mem R/W opcode
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xC0: # example: RET NZ
if !flags.Z: # cc=true
lsb = read_memory(addr=SP); SP = SP + 1
msb = read_memory(addr=SP); SP = SP + 1
PC = unsigned_16(lsb=lsb, msb=msb)
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5 M6/M1
ALU op Previous
M-cycle M1 M2 M3/M1
ALU op Previous
# M2
if IR == 0xC0: # example: RET NZ
if !flags.Z: # cc=true
# M3
Z = read_memory(addr=SP); SP = SP + 1
# M4
W = read_memory(addr=SP); SP = SP + 1
# M5
PC = WZ
# M6/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
else: # cc=false
# M3
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
121
RETI: Return from interrupt handler
Unconditional return from a function. Also enables interrupts by setting IME=1.
Opcode 0b11011001/0xD9 Duration 4 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xD9:
lsb = read_memory(addr=SP); SP = SP + 1
msb = read_memory(addr=SP); SP = SP + 1
PC = unsigned_16(lsb=lsb, msb=msb)
IME = 1
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5/M1
IDU op Previous SP ← SP + 1 SP ← SP + 1 PC ← PC + 1
ALU op Previous
# M2
if IR == 0xD9:
Z = read_memory(addr=SP); SP = SP + 1
# M3
W = read_memory(addr=SP); SP = SP + 1
# M4
PC = WZ; IME = 1
# M5/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
122
RST n: Restart / Call function (implied)
Unconditional function call to the absolute fixed address defined by the opcode.
Opcode 0b11xxx111/various Duration 4 machine cycles
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1 M2 M3 M4
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xDF: # example: RST 0x18
n = 0x18
SP = SP - 1
write_memory(addr=SP, data=msb(PC)); SP = SP - 1
write_memory(addr=SP, data=lsb(PC))
PC = unsigned_16(lsb=n, msb=0x00)
Detailed timing and pseudocode
M-cycle M1 M2 M3 M4 M5/M1
IDU op Previous SP ← SP - 1 SP ← SP - 1 SP ← SP PC ← PC + 1
ALU op Previous
# M2
if IR == 0xDF: # example: RST 0x18
SP = SP - 1
# M3
write_memory(addr=SP, data=msb(PC)); SP = SP - 1
# M4
write_memory(addr=SP, data=lsb(PC)); PC = 0x0018
# M5/M1
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
123
6.8 Miscellaneous instructions
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xF3:
IME = 0
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
ALU op Previous
# M2/M1
if IR == 0xF3:
# interrupt checking is suppressed so fetch_cycle(..) is not used
IR = read_memory(addr=PC); PC = PC + 1; IME = 0
124
EI: Enable interrupts
Schedules interrupt handling to be enabled after the next machine cycle.
Opcode 0b11111011/0xFB Duration 1 machine cycle
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0xFB:
IME_next = 1
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
ALU op Previous
# M2/M1
if IR == 0xFB:
IR, intr = fetch_cycle(addr=PC); PC = PC + 1; IME = 1
125
NOP: No operation
No operation. This instruction doesn’t do anything, but can be used to add a delay of one ma-
chine cycle and increment PC by one.
Opcode 0b00000000/0x00 Duration 1 machine cycle
Length 1 byte: opcode Flags -
Simple timing and pseudocode
M-cycle M1
opcode = read_memory(addr=PC); PC = PC + 1
if opcode == 0x00:
# nothing
Detailed timing and pseudocode
M-cycle M1 M2/M1
IDU op Previous PC ← PC + 1
ALU op Previous
Misc op Previous
# M2/M1
if IR == 0x00:
IR, intr = fetch_cycle(addr=PC); PC = PC + 1
126
127
Part III
128
Chapter 7
Boot ROM
The Game Boy SoC includes a small embedded boot ROM, which can be mapped to the
0x0000-0x00FF memory area. While mapped, all reads from this area are handled by the boot
ROM instead of the external cartridge, and all writes to this area are ignored and cannot be
seen by external hardware (e.g. the cartridge MBC).
The boot ROM is enabled by default, so when the system exits the reset state and the CPU
starts execution from address 0x0000, it executes the boot ROM instead of instructions from
the cartridge ROM. The boot ROM is responsible for showing the initial logo, and checking that
a valid cartridge is inserted into the system. If the cartridge is valid, the boot ROM unmaps itself
before execution of the cartridge ROM starts at 0x0100. The cartridge ROM has no chance of
executing any instructions before the boot ROM is unmapped, which prevents the boot ROM
from being read byte by byte in normal conditions.
Warning
Don’t confuse the boot ROM with the additional SNES ROM in SGB/SGB2 that is executed
by the SNES CPU.
BOOT_OFF can only transition from 0b0 to 0b1, so once 0b1 has been written, the boot
ROM is permanently disabled until the next system reset. Writing 0b0 when BOOT_OFF
is 0b0 has no effect and doesn’t lock the boot ROM.
The 1-bit BOOT register controls mapping of the boot ROM. Once 0b1 has been written to it to
unmap the boot ROM, it can only be mapped again by resetting the system.
129
Type CRC32 MD5 SHA1
DMG 59c8598e 32fbbd84168d3482956eb3c5051637f5 4ed31ec6b0b175bb109c0eb5fd3d193da823339f
130
Chapter 8
Warning
Avoid writing 0xE0-0xFF to the DMA register, because some poorly designed flash carts
can trigger bus conflicts or other dangerous behaviour.
131
OAM DMA address decoding
The OAM DMA controller uses a simplified address decoding scheme, which leads to some
addresses being unusable as source addresses. Unlike normal memory accesses, OAM DMA
transfers interpret all accesses in the 0xA000-0xFFFF range as external RAM transfers. For ex-
ample, if the OAM DMA wants to read 0xFF00, it will output 0xFF00 on the external address
bus and will assert the external RAM chip select signal. The P1 register which is normally at
0xFF00 is not involved at all, because OAM DMA address decoding only uses the external bus
and the video RAM bus. Instead, the resulting behaviour depends on several factors, including
the connected cartridge. Some flash carts are not prepared for this unexpected scenario, and
a bus conflict or worse behaviour can happen.
132
Chapter 9
133
Chapter 10
134
Chapter 11
Serial communication
bit 7 SIO_EN
bit 6-1 Unimplemented: Ignored during writes, reads are undefined
bit 0 SIO_CLK
135
Part IV
136
Chapter 12
The majority of games for the original Game Boy use the MBC1 chip. MBC1 supports ROM sizes
up to 16 Mbit (128 banks of 0x4000 bytes) and RAM sizes up to 256 Kbit (4 banks of 0x2000
bytes). The information in this section is based on my MBC1 research, Tauwasser’s research
notes [6], and Pan Docs [7].
Caveat
These registers don’t have any standard names and are usually referred to using their
address ranges or purposes instead. This document uses names to clarify which register
is meant when referring to one.
The MBC1 chip includes four registers that affect the behaviour of the chip. Of the cartridge
bus address signals, only A13-A15 are connected to the MBC, so lower address bits don’t matter
when the CPU is accessing the MBC and all registers are effectively mapped to address ranges
instead of single addresses. All registers are smaller than 8 bits, and unused bits are simply
ignored during writes. The registers are not directly readable.
137
🧩 Speculation
We don’t know the physical implementation of RAMG, but it’s certainly possible that the
0b1010 bit pattern check is done at write time and the register actually consists of just a
single bit.
138
Register 12.4: 0x6000-0x7FFF - MODE - MBC1 mode register
U U U U U U U W-0
MODE
bit 7 6 5 4 3 2 1 bit 0
Warning
Most documentation, including Pan Docs [7], calls value 0b0 ROM banking mode, and
value 0b1 RAM banking mode. This terminology reflects the common use cases, but “RAM
banking” is slightly misleading because value 0b1 also affects ROM reads in multicart
cartridges and cartridges that have a 8 or 16 Mbit ROM chip.
139
Value of the BANK 1 register 0b10010
Value of the BANK 2 register 0b01
Effective ROM bank number
0b0110010 (= 50 = 0x32)
(reading 0x4000-0x7FFF)
Effective ROM bank number
0b0000000 (= 0 = 0x00)
(reading 0x0000-0x3FFF, MODE = 0b0)
Effective ROM bank number
0b0100000 (= 32 = 0x20)
(reading 0x0000-0x3FFF, MODE = 0b1)
140
Value of the BANK 2 register 0b10
Address being read 0b1011 0001 0010 0011 (= 0xB123)
Actual physical RAM address 0b101 0001 0010 0011 (= 0x5123)
Detecting multicarts
MBC1 multicarts are not detectable by simply looking at the ROM header, because the ROM type
value is just one of the normal MBC1 values. However, detection is possible by going through
BANK2 values and looking at “bank 0” of each multicart game and doing some heuristics based
141
on the header data. All the included games, including the game selection menu, have proper
header data. One example of a good heuristic is logo data verification.
So, if you have a 8 Mbit cart with MBC1, first assume that it’s a multicart and bank numbers
are 6-bit values. Set BANK1 to zero and loop through the four possible BANK2 values while
checking the data at 0x0104-0x0133. In other words, check logo data starting from physical
ROM locations 0x00104, 0x40104, 0x80104, and 0xC0104. If proper logo data exists with most
of the BANK2 values, the cart is most likely a multicart. Note that multicarts can just have two
actual games, so one of the locations might not have the header data in place.
142
Chapter 13
MBC2 supports ROM sizes up to 2 Mbit (16 banks of 0x4000 bytes) and includes an internal
512x4 bit RAM array, which is its unique feature. The information in this section is based on my
MBC2 research, Tauwasser’s research notes [8], and Pan Docs [7].
🧩 Speculation
MBC1 is strictly more powerful than MBC2 because it supports more ROM and RAM. This
raises a very important question: why does MBC2 exist? It’s possible that Nintendo tried
to integrate a small amount of RAM on the MBC chip for cost reasons, but it seems that
this didn’t work out very well since all later MBCs revert this design decision and use
separate RAM chips.
Caveat
These registers don’t have any standard names and are usually referred to using one of
their addresses or purposes instead. This document uses names to clarify which register
is meant when referring to one.
The MBC2 chip includes two registers that affect the behaviour of the chip. The registers
are mapped a bit differently compared to other MBCs. Both registers are accessible within
0x0000-0x3FFF, and within that range, the register is chosen based on the A8 address signal.
In practice, this means that the registers are mapped to memory in an alternating pattern. For
example, 0x0000, 0x2000 and 0x3000 are RAMG, and 0x0100, 0x2100 and 0x3100 are ROMB.
Both registers are smaller than 8 bits, and unused bits are simply ignored during writes. The
registers are not directly readable.
Register 13.1: 0x0000-0x3FFF when A8=0b0 - RAMG - MBC2 RAM gate register
U U U U W-0 W-0 W-0 W-0
RAMG<3:0>
bit 7 6 5 4 3 2 1 bit 0
143
When RAM access is disabled, all writes to the external RAM area 0xA000-0xBFFF are ignored,
and reads return undefined values. Pan Docs recommends disabling RAM when it’s not being
accessed to protect the contents [7].
🧩 Speculation
We don’t know the physical implementation of RAMG, but it’s certainly possible that the
0b1010 bit pattern check is done at write time and the register actually consists of just a
single bit.
Register 13.2: 0x0000-0x3FFF when A8=0b1 - ROMB - MBC2 ROM bank register
U U U U W-0 W-0 W-0 W-1
ROMB<3:0>
bit 7 6 5 4 3 2 1 bit 0
144
MBC2 RAM is only 4-bit RAM, so the upper 4 bits of data do not physically exist in the chip.
When writing to it, the upper 4 bits are ignored. When reading from it, the upper 4 data signals
are not driven by the chip, so their content is undefined and should not be relied on.
MBC2 RAM consists of 512 addresses, so only A0-A8 matter when accessing the RAM region.
There is no banking, and the 0xA000-0xBFFF area is larger than the RAM, so the addresses
wrap around. For example, accessing 0xA000 is the same as accessing 0xA200, so it is possible
to write to the former address and later read the written data using the latter address.
145
Chapter 14
MBC3 supports ROM sizes up to 16 Mbit (128 banks of 0x4000 bytes), and RAM sizes up to 256
Kbit (4 banks of 0x2000 bytes). It also includes a real-time clock (RTC) that can be clocked with
a quartz crystal on the cartridge even when the Game Boy is powered down. The information
in this section is based on my MBC3 research, and Pan Docs [7].
146
Chapter 15
MBC30 is a variant of MBC3 used by Japanese Pokemon Crystal to support a larger ROM chip
and a larger RAM chip. Featurewise MBC30 is almost identical to MBC3, but supports ROM sizes
up to 32 Mbit (256 banks of 0x4000 bytes), and RAM sizes up to 512 Kbit (8 banks of 0x2000
bytes). Information in this section is based on my MBC30 research.
Warning
The circuit board of Japanese Pokemon Crystal includes a 1 Mbit RAM chip, but MBC30
is limited to 512 Kbit RAM. One of the RAM address pins is unused, so half of the RAM is
wasted and is inaccessible without modifications. So, the game only uses 512 Kbit and
there is a mismatch between accessible and the physical amounts of RAM.
147
Chapter 16
The majority of games for Game Boy Color use the MBC5 chip. MBC5 supports ROM sizes up
to 64 Mbit (512 banks of 0x4000 bytes), and RAM sizes up to 1 Mbit (16 banks of 0x2000 bytes).
The information in this section is based on my MBC5 research, and The Cycle-Accurate Game
Boy Docs [9].
🧩 Speculation
We don’t know the physical implementation of RAMG, but it’s certainly possible that the
0b00001010 bit pattern check is done at write time and the register actually consists of
just a single bit.
148
Register 16.3: 0x3000-0x3FFF - ROMB1 - MBC5 upper ROM bank register
U U U U U U U W-0
ROMB1
bit 7 6 5 4 3 2 1 bit 0
149
Chapter 17
MBC6 supports ROM sizes up to 16 Mbit (256 banks of 0x2000 bytes), and RAM sizes up to 4 Mbit
(128 banks of 0x1000 bytes). The information in this section is based on my MBC6 research.
150
Chapter 18
MBC7
TODO.
151
Chapter 19
HuC-1 supports ROM sizes up to 8 Mbit (64 banks of 0x4000 bytes), and RAM sizes up to 256
Kbit (4 banks of 0x2000 bytes). It also includes a sensor and a LED for infrared communication.
The information in this section is based on my HuC-1 research.
152
Chapter 20
HuC-3 supports ROM sizes up to 16 Mbit (128 banks of 0x4000 bytes), and RAM sizes up to 1
Mbit (16 banks of 0x2000 bytes). Like HuC-1, it includes support for infrared communication,
but also includes a real-time-clock (RTC) and output pins used to control a piezoelectric buzzer.
The information in this section is based on my HuC-3 research.
153
Chapter 21
MMM01
TODO.
154
Chapter 22
TAMA5
TODO.
155
Appendices
156
Appendix A
157
x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf
0x NOP LD BC,nn LD (BC),A INC BC INC B DEC B LD B,n RLCA LD (nn),SP ADD HL,BC LD A,(BC) DEC BC INC C DEC C LD C,n RRCA
1x STOP LD DE,nn LD (DE),A INC DE INC D DEC D LD D,n RLA JR e ADD HL,DE LD A,(DE) DEC DE INC E DEC E LD E,n RRA
2x JR NZ,e LD HL,nn LD (HL+),A INC HL INC H DEC H LD H,n DAA JR Z,e ADD HL,HL LD A,(HL+) DEC HL INC L DEC L LD L,n CPL
3x JR NC,e LD SP,nn LD (HL-),A INC SP INC (HL) DEC (HL) LD (HL),n SCF JR C,e ADD HL,SP LD A,(HL-) DEC SP INC A DEC A LD A,n CCF
4x LD B,B LD B,C LD B,D LD B,E LD B,H LD B,L LD B,(HL) LD B,A LD C,B LD C,C LD C,D LD C,E LD C,H LD C,L LD C,(HL) LD C,A
5x LD D,B LD D,C LD D,D LD D,E LD D,H LD D,L LD D,(HL) LD D,A LD E,B LD E,C LD E,D LD E,E LD E,H LD E,L LD E,(HL) LD E,A
6x LD H,B LD H,C LD H,D LD H,E LD H,H LD H,L LD H,(HL) LD H,A LD L,B LD L,C LD L,D LD L,E LD L,H LD L,L LD L,(HL) LD L,A
7x LD (HL),B LD (HL),C LD (HL),D LD (HL),E LD (HL),H LD (HL),L HALT LD (HL),A LD A,B LD A,C LD A,D LD A,E LD A,H LD A,L LD A,(HL) LD A,A
8x ADD B ADD C ADD D ADD E ADD H ADD L ADD (HL) ADD A ADC B ADC C ADC D ADC E ADC H ADC L ADC (HL) ADC A
9x SUB B SUB C SUB D SUB E SUB H SUB L SUB (HL) SUB A SBC B SBC C SBC D SBC E SBC H SBC L SBC (HL) SBC A
ax AND B AND C AND D AND E AND H AND L AND (HL) AND A XOR B XOR C XOR D XOR E XOR H XOR L XOR (HL) XOR A
bx OR B OR C OR D OR E OR H OR L OR (HL) OR A CP B CP C CP D CP E CP H CP L CP (HL) CP A
cx RET NZ POP BC JP NZ,nn JP nn CALL NZ,nn PUSH BC ADD n RST 0x00 RET Z RET JP Z,nn CB op CALL Z,nn CALL nn ADC n RST 0x08
dx RET NC POP DE JP NC,nn - CALL NC,nn PUSH DE SUB n RST 0x10 RET C RETI JP C,nn - CALL C,nn - SBC n RST 0x18
ex LDH (n),A POP HL LDH (C),A - - PUSH HL AND n RST 0x20 ADD SP,e JP HL LD (nn),A - - - XOR n RST 0x28
fx LDH A,(n) POP AF LDH A,(C) DI - PUSH AF OR n RST 0x30 LD HL,SP+e LD SP,HL LD A,(nn) EI - - CP n RST 0x38
8-bit loads 16-bit loads 8-bit arithmetic/logical 16-bit arithmetic Rotates, shifts, and bit operations Control flow Miscellaneous
Undefined
158
x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf
0x RLC B RLC C RLC D RLC E RLC H RLC L RLC (HL) RLC A RRC B RRC C RRC D RRC E RRC H RRC L RRC (HL) RRC A
1x RL B RL C RL D RL E RL H RL L RL (HL) RL A RR B RR C RR D RR E RR H RR L RR (HL) RR A
2x SLA B SLA C SLA D SLA E SLA H SLA L SLA (HL) SLA A SRA B SRA C SRA D SRA E SRA H SRA L SRA (HL) SRA A
3x SWAP B SWAP C SWAP D SWAP E SWAP H SWAP L SWAP (HL) SWAP A SRL B SRL C SRL D SRL E SRL H SRL L SRL (HL) SRL A
4x BIT 0,B BIT 0,C BIT 0,D BIT 0,E BIT 0,H BIT 0,L BIT 0,(HL) BIT 0,A BIT 1,B BIT 1,C BIT 1,D BIT 1,E BIT 1,H BIT 1,L BIT 1,(HL) BIT 1,A
5x BIT 2,B BIT 2,C BIT 2,D BIT 2,E BIT 2,H BIT 2,L BIT 2,(HL) BIT 2,A BIT 3,B BIT 3,C BIT 3,D BIT 3,E BIT 3,H BIT 3,L BIT 3,(HL) BIT 3,A
6x BIT 4,B BIT 4,C BIT 4,D BIT 4,E BIT 4,H BIT 4,L BIT 4,(HL) BIT 4,A BIT 5,B BIT 5,C BIT 5,D BIT 5,E BIT 5,H BIT 5,L BIT 5,(HL) BIT 5,A
7x BIT 6,B BIT 6,C BIT 6,D BIT 6,E BIT 6,H BIT 6,L BIT 6,(HL) BIT 6,A BIT 7,B BIT 7,C BIT 7,D BIT 7,E BIT 7,H BIT 7,L BIT 7,(HL) BIT 7,A
8x RES 0,B RES 0,C RES 0,D RES 0,E RES 0,H RES 0,L RES 0,(HL) RES 0,A RES 1,B RES 1,C RES 1,D RES 1,E RES 1,H RES 1,L RES 1,(HL) RES 1,A
9x RES 2,B RES 2,C RES 2,D RES 2,E RES 2,H RES 2,L RES 2,(HL) RES 2,A RES 3,B RES 3,C RES 3,D RES 3,E RES 3,H RES 3,L RES 3,(HL) RES 3,A
ax RES 4,B RES 4,C RES 4,D RES 4,E RES 4,H RES 4,L RES 4,(HL) RES 4,A RES 5,B RES 5,C RES 5,D RES 5,E RES 5,H RES 5,L RES 5,(HL) RES 5,A
bx RES 6,B RES 6,C RES 6,D RES 6,E RES 6,H RES 6,L RES 6,(HL) RES 6,A RES 7,B RES 7,C RES 7,D RES 7,E RES 7,H RES 7,L RES 7,(HL) RES 7,A
cx SET 0,B SET 0,C SET 0,D SET 0,E SET 0,H SET 0,L SET 0,(HL) SET 0,A SET 1,B SET 1,C SET 1,D SET 1,E SET 1,H SET 1,L SET 1,(HL) SET 1,A
dx SET 2,B SET 2,C SET 2,D SET 2,E SET 2,H SET 2,L SET 2,(HL) SET 2,A SET 3,B SET 3,C SET 3,D SET 3,E SET 3,H SET 3,L SET 3,(HL) SET 3,A
ex SET 4,B SET 4,C SET 4,D SET 4,E SET 4,H SET 4,L SET 4,(HL) SET 4,A SET 5,B SET 5,C SET 5,D SET 5,E SET 5,H SET 5,L SET 5,(HL) SET 5,A
fx SET 6,B SET 6,C SET 6,D SET 6,E SET 6,H SET 6,L SET 6,(HL) SET 6,A SET 7,B SET 7,C SET 7,D SET 7,E SET 7,H SET 7,L SET 7,(HL) SET 7,A
159
Appendix B
160
bit 7 6 5 4 3 2 1 bit 0
0xFF00 P1 P15 buttons P14 d-pad P13 start P12 select P11 B P10 A
0xFF01 SB SB<7:0>
0xFF02 SC SIO_EN SIO_FAST SIO_CLK
0xFF03
0xFF04 DIV DIVH<7:0>
0xFF05 TIMA TIMA<7:0>
0xFF06 TMA TMA<7:0>
0xFF07 TAC TAC_EN TAC_CLK<1:0>
0xFF08
0xFF09
0xFF0A
0xFF0B
0xFF0C
0xFF0D
0xFF0E
0xFF0F IF IF_JOYPAD IF_SERIAL IF_TIMER IF_STAT IF_VBLANK
0xFF10 NR10
0xFF11 NR11
0xFF12 NR12
0xFF13 NR13
0xFF14 NR14
0xFF15
0xFF16 NR21
0xFF17 NR22
0xFF18 NR23
0xFF19 NR24
0xFF1A NR30
0xFF1B NR31
0xFF1C NR32
0xFF1D NR33
0xFF1E NR34
0xFF1F
bit 7 6 5 4 3 2 1 bit 0
Table B.3: 0xFFxx registers: 0xFF00-0xFF1F
161
bit 7 6 5 4 3 2 1 bit 0
0xFF20 NR41
0xFF21 NR42
0xFF22 NR43
0xFF23 NR44
0xFF24 NR50
0xFF25 NR51
0xFF26 NR52
0xFF27
0xFF28
0xFF29
0xFF2A
0xFF2B
0xFF2C
0xFF2D
0xFF2E
0xFF2F
0xFF30 WAV00
0xFF31 WAV01
0xFF32 WAV02
0xFF33 WAV03
0xFF34 WAV04
0xFF35 WAV05
0xFF36 WAV06
0xFF37 WAV07
0xFF38 WAV08
0xFF39 WAV09
0xFF3A WAV10
0xFF3B WAV11
0xFF3C WAV12
0xFF3D WAV13
0xFF3E WAV14
0xFF3F WAV15
bit 7 6 5 4 3 2 1 bit 0
Table B.4: 0xFFxx registers: 0xFF20-0xFF3F
162
bit 7 6 5 4 3 2 1 bit 0
0xFF40 LCDC LCD_EN WIN_MAP WIN_EN TILE_SEL BG_MAP OBJ_SIZE OBJ_EN BG_EN
0xFF41 STAT INTR_LYC INTR_M2 INTR_M1 INTR_M0 LYC_STAT LCD_MODE<1:0>
0xFF42 SCY
0xFF43 SCX
0xFF44 LY
0xFF45 LYC
0xFF46 DMA DMA<7:0>
0xFF47 BGP
0xFF48 OBP0
0xFF49 OBP1
0xFF4A WY
0xFF4B WX
0xFF4C ????
0xFF4D KEY1 KEY1_FAST KEY1_EN
0xFF4E
0xFF4F VBK VBK<1:0>
0xFF50 BOOT BOOT_OFF
0xFF51 HDMA1
0xFF52 HDMA2
0xFF53 HDMA3
0xFF54 HDMA4
0xFF55 HDMA5
0xFF56 RP
0xFF57
0xFF58
0xFF59
0xFF5A
0xFF5B
0xFF5C
0xFF5D
0xFF5E
0xFF5F
bit 7 6 5 4 3 2 1 bit 0
Table B.5: 0xFFxx registers: 0xFF40-0xFF5F
163
bit 7 6 5 4 3 2 1 bit 0
0xFF60 ????
0xFF61
0xFF62
0xFF63
0xFF64
0xFF65
0xFF66
0xFF67
0xFF68 BCPS
0xFF69 BPCD
0xFF6A OCPS
0xFF6B OCPD
0xFF6C ????
0xFF6D
0xFF6E
0xFF6F
0xFF70 SVBK SVBK<1:0>
0xFF71
0xFF72 ????
0xFF73 ????
0xFF74 ????
0xFF75 ????
0xFF76 PCM12 PCM12_CH2 PCM12_CH1
0xFF77 PCM34 PCM34_CH4 PCM34_CH3
0xFF78
0xFF79
0xFF7A
0xFF7B
0xFF7C
0xFF7D
0xFF7E
0xFF7F
0xFFFF IE IE_UNUSED<2:0> IE_JOYPAD IE_SERIAL IE_TIMER IE_STAT IE_VBLANK
bit 7 6 5 4 3 2 1 bit 0
Table B.6: 0xFFxx registers: 0xFF60-0xFF7F, 0xFFFF
164
Appendix C
CLK 4 MiHz
PHI 1 MiHz
A0-A14
RD
WR
A15
CS
Data
Figure C.5: External bus idle machine cycle
RD RD
WR WR
A15 A15
CS CS
Data data Data data
a) 0x0000-0x7FFF¹ b) 0xA000-0xFDFF
CLK 4 MiHz
PHI 1 MiHz
A0-A14 addr
RD
WR
A15
CS
Data
c) 0xFE00-0xFFFF
165
CLK 4 MiHz CLK 4 MiHz
PHI 1 MiHz PHI 1 MiHz
A0-A14 addr A0-A14 addr
RD RD
WR WR
A15 A15
CS CS
Data data Data data
a) 0x0000-0x7FFF¹ b) 0xA000-0xFDFF
CLK 4 MiHz
PHI 1 MiHz
A0-A14 addr
RD
WR
A15
CS
Data
c) 0xFE00-0xFFFF
RD RD
WR WR
A15 A15
CS CS
Data data Data data
a) 0x0000-0x7FFF¹ b) 0xA000-0xFFFF
Figure C.8: External bus timings for OAM DMA read machine cycles
¹Does not apply to 0x0000-0x00FF accesses while the boot ROM is enabled. Boot ROM accesses do not affect
the external bus, so it is in the idle state.
166
Appendix D
Chip pinouts
D.1 CPU chips D.2 Cartridge chips
167
Bibliography
[1] “Microcomputers Data Book (1990).” Sharp Corporation. [Online]. Available: https://
archive.org/details/bitsavers_sharpdataBomputersDataBook_31076011
[2] “Microcomputer Data Book (1996).” Sharp Corporation. [Online]. Available: https://
archive.org/details/bitsavers_sharpdataBomputerDataBook_13840187
[3] “SM8311/SM8313/SM8314/SM8315 - 8-Bit Single-Chip Microcomputers (Controllers For
Home Appliances).” Sharp Corporation.
[4] Costis Sideris, “The quest for dumping GameBoy Boot ROMs!.” [Online]. Available: http://
www.its.caltech.edu/~costis/sgb_hack/
[5] gekkio, “Dumping the Super Game Boy 2 boot ROM.” [Online]. Available: https://gekkio.
fi/blog/2015/dumping-the-super-game-boy-2-boot-rom/
[6] Tauwasser, “MBC1 - Tauwasser's Wiki.” [Online]. Available: https://wiki.tauwasser.eu/view/
MBC1
[7] Pan of ATX, M. Fayzullin, P. Felber, P. Robson, and M. Korth, “Pan Docs - Everything
You Always Wanted To Know About GAMEBOY.” [Online]. Available: http://bgb.bircd.org/
pandocs.htm
[8] Tauwasser, “MBC2 - Tauwasser's Wiki.” [Online]. Available: https://wiki.tauwasser.eu/view/
MBC2
[9] Antonio Niño Díaz (AntonioND), “The Cycle-Accurate Game Boy Docs.” [Online]. Available:
https://github.com/AntonioND/giibiiadvance/tree/master/docs
[10] “Gameboy CPU (LR35902) instruction set.” [Online]. Available: http://www.pastraiser.com/
cpu/gameboy/gameboy_opcodes.html
168