diff --git a/src/CPU_Instruction_Set.md b/src/CPU_Instruction_Set.md index 3028d21f..7a14e6d7 100644 --- a/src/CPU_Instruction_Set.md +++ b/src/CPU_Instruction_Set.md @@ -1,151 +1,192 @@ # CPU Instruction Set -Tables below specify the mnemonic, encoding, clock cycles, affected -flags (ordered as znhc), and description. The timings assume a CPU -clock frequency of 4.194304 MHz (or 8.4 MHz for CGB in double speed -mode), called "T-states". Because all Game Boy timings are divisible -by 4, many people specify timings and clock frequency divided by 4, -called "M-cycles". - -## 8-bit Load instructions - -Mnemonic | Encoding | Clock cycles | Flags | Description ------------------|----------|--------------|-------|------------- - ld r,r | xx | 4 | ---- | r=r - ld r,n | xx nn | 8 | ---- | r=n - ld r,(HL) | xx | 8 | ---- | r=(HL) - ld (HL),r | 7x | 8 | ---- | (HL)=r - ld (HL),n | 36 nn | 12 | ---- | (HL)=n - ld A,(BC) | 0A | 8 | ---- | A=(BC) - ld A,(DE) | 1A | 8 | ---- | A=(DE) - ld A,(nn) | FA | 16 | ---- | A=(nn) - ld (BC),A | 02 | 8 | ---- | (BC)=A - ld (DE),A | 12 | 8 | ---- | (DE)=A - ld (nn),A | EA | 16 | ---- | (nn)=A - ld A,(FF00+n) | F0 nn | 12 | ---- | read from io-port n (memory FF00+n) - ld (FF00+n),A | E0 nn | 12 | ---- | write to io-port n (memory FF00+n) - ld A,(FF00+C) | F2 | 8 | ---- | read from io-port C (memory FF00+C) - ld (FF00+C),A | E2 | 8 | ---- | write to io-port C (memory FF00+C) - ldi (HL),A | 22 | 8 | ---- | (HL)=A, HL=HL+1 - ldi A,(HL) | 2A | 8 | ---- | A=(HL), HL=HL+1 - ldd (HL),A | 32 | 8 | ---- | (HL)=A, HL=HL-1 - ldd A,(HL) | 3A | 8 | ---- | A=(HL), HL=HL-1 - -## 16-bit Load instructions - -Mnemonic | Encoding | Clock cycles | Flags | Description ------------------|----------|--------------|-------|------------- - ld rr,nn | x1 nn nn | 12 | ---- | rr=nn (rr may be BC,DE,HL or SP) - ld (nn),SP | 08 nn nn | 20 | ---- | (nn)=SP - ld SP,HL | F9 | 8 | ---- | SP=HL - push rr | x5 | 16 | ---- | SP=SP-2 (SP)=rr ; rr may be BC,DE,HL,AF - pop rr | x1 | 12 | (AF) | rr=(SP) SP=SP+2 ; rr may be BC,DE,HL,AF - -## 8-bit Arithmetic/Logic instructions - -Mnemonic | Encoding | Clock cycles | Flags | Description ------------------|----------|--------------|-------|------------- - add A,r | 8x | 4 | z0hc | A=A+r - add A,n | C6 nn | 8 | z0hc | A=A+n - add A,(HL) | 86 | 8 | z0hc | A=A+(HL) - adc A,r | 8x | 4 | z0hc | A=A+r+cy - adc A,n | CE nn | 8 | z0hc | A=A+n+cy - adc A,(HL) | 8E | 8 | z0hc | A=A+(HL)+cy - sub r | 9x | 4 | z1hc | A=A-r - sub n | D6 nn | 8 | z1hc | A=A-n - sub (HL) | 96 | 8 | z1hc | A=A-(HL) - sbc A,r | 9x | 4 | z1hc | A=A-r-cy - sbc A,n | DE nn | 8 | z1hc | A=A-n-cy - sbc A,(HL) | 9E | 8 | z1hc | A=A-(HL)-cy - and r | Ax | 4 | z010 | A=A & r - and n | E6 nn | 8 | z010 | A=A & n - and (HL) | A6 | 8 | z010 | A=A & (HL) - xor r | Ax | 4 | z000 | A=A xor r - xor n | EE nn | 8 | z000 | A=A xor n - xor (HL) | AE | 8 | z000 | A=A xor (HL) - or r | Bx | 4 | z000 | A=A \| r - or n | F6 nn | 8 | z000 | A=A \| n - or (HL) | B6 | 8 | z000 | A=A \| (HL) - cp r | Bx | 4 | z1hc | compare A-r - cp n | FE nn | 8 | z1hc | compare A-n - cp (HL) | BE | 8 | z1hc | compare A-(HL) - inc r | xx | 4 | z0h- | r=r+1 - inc (HL) | 34 | 12 | z0h- | (HL)=(HL)+1 - dec r | xx | 4 | z1h- | r=r-1 - dec (HL) | 35 | 12 | z1h- | (HL)=(HL)-1 - daa | 27 | 4 | z-0c | decimal adjust A - cpl | 2F | 4 | -11- | A = A xor FF - -## 16-bit Arithmetic/Logic instructions - -Mnemonic | Encoding | Clock cycles | Flags | Description ------------------|----------|--------------|-------|------------- - add HL,rr | x9 | 8 | -0hc | HL = HL+rr ; rr may be BC,DE,HL,SP - inc rr | x3 | 8 | ---- | rr = rr+1 ; rr may be BC,DE,HL,SP - dec rr | xB | 8 | ---- | rr = rr-1 ; rr may be BC,DE,HL,SP - add SP,dd | E8 dd | 16 | 00hc | SP = SP +/- dd ; dd is 8-bit signed number - ld HL,SP+dd | F8 dd | 12 | 00hc | HL = SP +/- dd ; dd is 8-bit signed number - -## Rotate and Shift instructions - -Mnemonic | Encoding | Clock cycles | Flags | Description ------------------|----------|--------------|-------|------------- - rlca | 07 | 4 | 000c | rotate A left - rla | 17 | 4 | 000c | rotate A left through carry - rrca | 0F | 4 | 000c | rotate A right - rra | 1F | 4 | 000c | rotate A right through carry - rlc r | CB 0x | 8 | z00c | rotate left - rlc (HL) | CB 06 | 16 | z00c | rotate left - rl r | CB 1x | 8 | z00c | rotate left through carry - rl (HL) | CB 16 | 16 | z00c | rotate left through carry - rrc r | CB 0x | 8 | z00c | rotate right - rrc (HL) | CB 0E | 16 | z00c | rotate right - rr r | CB 1x | 8 | z00c | rotate right through carry - rr (HL) | CB 1E | 16 | z00c | rotate right through carry - sla r | CB 2x | 8 | z00c | shift left arithmetic (b0=0) - sla (HL) | CB 26 | 16 | z00c | shift left arithmetic (b0=0) - swap r | CB 3x | 8 | z000 | exchange low/hi-nibble - swap (HL) | CB 36 | 16 | z000 | exchange low/hi-nibble - sra r | CB 2x | 8 | z00c | shift right arithmetic (b7=b7) - sra (HL) | CB 2E | 16 | z00c | shift right arithmetic (b7=b7) - srl r | CB 3x | 8 | z00c | shift right logical (b7=0) - srl (HL) | CB 3E | 16 | z00c | shift right logical (b7=0) - -## Single-bit Operation instructions - -Mnemonic | Encoding | Clock cycles | Flags | Description ------------------|----------|--------------|-------|------------- - bit n,r | CB xx | 8 | z01- | test bit n - bit n,(HL) | CB xx | 12 | z01- | test bit n - set n,r | CB xx | 8 | ---- | set bit n - set n,(HL) | CB xx | 16 | ---- | set bit n - res n,r | CB xx | 8 | ---- | reset bit n - res n,(HL) | CB xx | 16 | ---- | reset bit n - -## CPU Control instructions - -Mnemonic | Encoding | Clock cycles | Flags | Description ------------------|----------|--------------|-------|------------- - ccf | 3F | 4 | -00c | cy=cy xor 1 - scf | 37 | 4 | -001 | cy=1 - nop | 00 | 4 | ---- | no operation - halt | 76 | N*4 | ---- | halt until interrupt occurs (low power) - stop | 10 00 | ? | ---- | low power standby mode (VERY low power) - di | F3 | 4 | ---- | disable interrupts, IME=0 - ei | FB | 4 | ---- | enable interrupts, IME=1 - -## Jump instructions - -Mnemonic | Encoding | Clock cycles | Flags | Description ------------------|----------|--------------|-------|------------- - jp nn | C3 nn nn | 16 | ---- | jump to nn, PC=nn - jp HL | E9 | 4 | ---- | jump to HL, PC=HL - jp f,nn | xx nn nn | 16/12 | ---- | conditional jump if nz,z,nc,c - jr PC+dd | 18 dd | 12 | ---- | relative jump to nn (PC=PC+8-bit signed) - jr f,PC+dd | xx dd | 12/8 | ---- | conditional relative jump if nz,z,nc,c - call nn | CD nn nn | 24 | ---- | call to nn, SP=SP-2, (SP)=PC, PC=nn - call f,nn | xx nn nn | 24/12 | ---- | conditional call if nz,z,nc,c - ret | C9 | 16 | ---- | return, PC=(SP), SP=SP+2 - ret f | xx | 20/8 | ---- | conditional return if nz,z,nc,c - reti | D9 | 16 | ---- | return and enable interrupts (IME=1) - rst n | xx | 16 | ---- | call to 00,08,10,18,20,28,30,38 +:::tip + +If you are looking for textual explanations of what each each instruction does, please read [gbz80(7)](http://rgbds.gbdev.io/docs/gbz80.7); if you want a compact reference card/cheat sheet of each opcode and its flag effects, please consult [the optables](http://gbdev.io/gb-opcodes/optables) (whose [octal view](http://gbdev.io/gb-opcodes/optables/octal) makes most encoding patterns more apparent). + +::: + + + +The Game Boy's SM83 processor possesses a CISC, variable-length instruction set. +This page attempts to shed some light on how the CPU decodes the raw bytes fed into it into instructions. + +The first byte of each instruction is typically called the "opcode" (for "operation code"). +By noticing that some instructions perform identical operations but with different parameters, they can be grouped together; for example, `inc bc`, `inc de`, `inc hl`, and `inc sp` differ only in what 16-bit register they modify. + +In each table, one line represents one such grouping. +Since many groupings have some variation, the variation has to be encoded in the instruction; for example, the above four instructions will be collectively referred to as `inc r16`. +Here are the possible placeholders and their values: + +{{#bits 8 < + "r8" 0:"b" 1:"c" 2:"d" 3:"e" 4:"h" 5:"l" 6:"[hl]" 7:"a" ; + "r16" 0:"bc" 1:"de" 2:"hl" 3:"sp" ; + "r16stk" 0:"bc" 1:"de" 2:"hl" 3:"af" ; + "r16mem" 0:"bc" 1:"de" 2:"hl+" 3:"hl-" ; + "cond" 0:"nz" 1:"z" 2:"nc" 3:"c" ; + "b3" 0-7:"A 3-bit bit index" ; + "tgt3" 0-7:"rst's target address, divided by 8" ; + "imm8" 0-7:"The following byte" ; + "imm16" 0-7:"The following two bytes, in little-endian order" ; +}} + +These last two are a little special: if they are present in the instruction's mnemonic, it means that the instruction is 1 (`imm8`) / 2 (`imm16`) extra bytes long. + +:::tip + +`[hl+]` and `[hl-]` can also be notated `[hli]` and `[hld]` respectively (as in **i**ncrement and **d**ecrement). + +::: + +Groupings have been loosely associated based on what they do into separate tables; those have no particular ordering, and are purely for readability and convenience. +Finally, the instruction "families" have been further grouped into four "blocks", differentiated by the first two bits of the opcode. + +## Block 0 + +{{#bits 8 > + "nop" 7:"0" 6:"0" 5:"0" 4:"0" 3:"0" 2:"0" 1:"0" 0:"0" +}} + +{{#bits 8 > + "ld r16, imm16" 7:"0" 6:"0" 5-4:"Dest (r16)" 3:"0" 2:"0" 1:"0" 0:"1" ; + "ld [r16mem], a" 7:"0" 6:"0" 5-4:"Dest (r16mem)" 3:"0" 2:"0" 1:"1" 0:"0" ; + "ld a, [r16mem]" 7:"0" 6:"0" 5-4:"Source (r16mem)" 3:"1" 2:"0" 1:"1" 0:"0" ; + "ld [imm16], sp" 7:"0" 6:"0" 5:"0" 4:"0" 3:"1" 2:"0" 1:"0" 0:"0" ; +}} + +{{#bits 8 > + "inc r16" 7:"0" 6:"0" 5-4:"Operand (r16)" 3:"0" 2:"0" 1:"1" 0:"1" ; + "dec r16" 7:"0" 6:"0" 5-4:"Operand (r16)" 3:"1" 2:"0" 1:"1" 0:"1" ; + "add hl, r16" 7:"0" 6:"0" 5-4:"Operand (r16)" 3:"1" 2:"0" 1:"0" 0:"1" ; +}} + +{{#bits 8 > + "inc r8" 7:"0" 6:"0" 5-3:"Operand (r8)" 2:"1" 1:"0" 0:"0" ; + "dec r8" 7:"0" 6:"0" 5-3:"Operand (r8)" 2:"1" 1:"0" 0:"1" ; +}} + +{{#bits 8 > + "ld r8, imm8" 7:"0" 6:"0" 5-3:"Dest (r8)" 2:"1" 1:"1" 0:"0" +}} + +{{#bits 8 > + "rlca" 7:"0" 6:"0" 5:"0" 4:"0" 3:"0" 2:"1" 1:"1" 0:"1" ; + "rrca" 7:"0" 6:"0" 5:"0" 4:"0" 3:"1" 2:"1" 1:"1" 0:"1" ; + "rla" 7:"0" 6:"0" 5:"0" 4:"1" 3:"0" 2:"1" 1:"1" 0:"1" ; + "rra" 7:"0" 6:"0" 5:"0" 4:"1" 3:"1" 2:"1" 1:"1" 0:"1" ; + "daa" 7:"0" 6:"0" 5:"1" 4:"0" 3:"0" 2:"1" 1:"1" 0:"1" ; + "cpl" 7:"0" 6:"0" 5:"1" 4:"0" 3:"1" 2:"1" 1:"1" 0:"1" ; + "scf" 7:"0" 6:"0" 5:"1" 4:"1" 3:"0" 2:"1" 1:"1" 0:"1" ; + "ccf" 7:"0" 6:"0" 5:"1" 4:"1" 3:"1" 2:"1" 1:"1" 0:"1" ; +}} + +{{#bits 8 > + "jr imm8" 7:"0" 6:"0" 5:"0" 4:"1" 3:"1" 2:"0" 1:"0" 0:"0" ; + "jr cond, imm8" 7:"0" 6:"0" 5:"1" 4-3:"Condition (cond)" 2:"0" 1:"0" 0:"0" ; +}} + +{{#bits 8 > + "stop" 7:"0" 6:"0" 5:"0" 4:"1" 3:"0" 2:"0" 1:"0" 0:"0" +}} + +[`stop`](<#Using the STOP Instruction>) is often considered a **two-byte** instruction, though [the second byte is not always ignored](https://gist.github.com/SonoSooS/c0055300670d678b5ae8433e20bea595#nop-and-stop). + +## Block 1: 8-bit register-to-register loads + +{{#bits 8 > + "ld r8, r8" 7:"0" 6:"1" 5-3:"Dest (r8)" 2-0:"Source (r8)" +}} + +**Exception**: trying to encode `ld [hl], [hl]` instead yields [the `halt` instruction](<#halt>): + +{{#bits 8 > + "halt" 7:"0" 6:"1" 5:"1" 4:"1" 3:"0" 2:"1" 1:"1" 0:"0" +}} + +## Block 2: 8-bit arithmetic + +{{#bits 8 > + "add a, r8" 7:"1" 6:"0" 5:"0" 4:"0" 3:"0" 2-0:"Operand (r8)" ; + "adc a, r8" 7:"1" 6:"0" 5:"0" 4:"0" 3:"1" 2-0:"Operand (r8)" ; + "sub a, r8" 7:"1" 6:"0" 5:"0" 4:"1" 3:"0" 2-0:"Operand (r8)" ; + "sbc a, r8" 7:"1" 6:"0" 5:"0" 4:"1" 3:"1" 2-0:"Operand (r8)" ; + "and a, r8" 7:"1" 6:"0" 5:"1" 4:"0" 3:"0" 2-0:"Operand (r8)" ; + "xor a, r8" 7:"1" 6:"0" 5:"1" 4:"0" 3:"1" 2-0:"Operand (r8)" ; + "or a, r8" 7:"1" 6:"0" 5:"1" 4:"1" 3:"0" 2-0:"Operand (r8)" ; + "cp a, r8" 7:"1" 6:"0" 5:"1" 4:"1" 3:"1" 2-0:"Operand (r8)" ; +}} + +## Block 3 + +{{#bits 8 > + "add a, imm8" 7:"1" 6:"1" 5:"0" 4:"0" 3:"0" 2:"1" 1:"1" 0:"0" ; + "adc a, imm8" 7:"1" 6:"1" 5:"0" 4:"0" 3:"1" 2:"1" 1:"1" 0:"0" ; + "sub a, imm8" 7:"1" 6:"1" 5:"0" 4:"1" 3:"0" 2:"1" 1:"1" 0:"0" ; + "sbc a, imm8" 7:"1" 6:"1" 5:"0" 4:"1" 3:"1" 2:"1" 1:"1" 0:"0" ; + "and a, imm8" 7:"1" 6:"1" 5:"1" 4:"0" 3:"0" 2:"1" 1:"1" 0:"0" ; + "xor a, imm8" 7:"1" 6:"1" 5:"1" 4:"0" 3:"1" 2:"1" 1:"1" 0:"0" ; + "or a, imm8" 7:"1" 6:"1" 5:"1" 4:"1" 3:"0" 2:"1" 1:"1" 0:"0" ; + "cp a, imm8" 7:"1" 6:"1" 5:"1" 4:"1" 3:"1" 2:"1" 1:"1" 0:"0" ; +}} + +{{#bits 8 > + "ret cond" 7:"1" 6:"1" 5:"0" 4-3:"Condition (cond)" 2:"0" 1:"0" 0:"0" ; + "ret" 7:"1" 6:"1" 5:"0" 4:"0" 3:"1" 2:"0" 1:"0" 0:"1" ; + "reti" 7:"1" 6:"1" 5:"0" 4:"1" 3:"1" 2:"0" 1:"0" 0:"1" ; + "jp cond, imm16" 7:"1" 6:"1" 5:"0" 4-3:"Condition (cond)" 2:"0" 1:"1" 0:"0" ; + "jp imm16" 7:"1" 6:"1" 5:"0" 4:"0" 3:"0" 2:"0" 1:"1" 0:"1" ; + "jp hl" 7:"1" 6:"1" 5:"1" 4:"0" 3:"1" 2:"0" 1:"0" 0:"1" ; + "call cond, imm16" 7:"1" 6:"1" 5:"0" 4-3:"Condition (cond)" 2:"1" 1:"0" 0:"0" ; + "call imm16" 7:"1" 6:"1" 5:"0" 4:"0" 3:"1" 2:"1" 1:"0" 0:"1" ; + "rst tgt3" 7:"1" 6:"1" 5-3:"Target (tgt3)" 2:"1" 1:"1" 0:"1" ; +}} + +{{#bits 8 > + "pop r16stk" 7:"1" 6:"1" 5-4:"Register (r16stk)" 3:"0" 2:"0" 1:"0" 0:"1" ; + "push r16stk" 7:"1" 6:"1" 5-4:"Register (r16stk)" 3:"0" 2:"1" 1:"0" 0:"1" ; +}} + +{{#bits 8 > + "Prefix (see block below)" 7:"1" 6:"1" 5:"0" 4:"0" 3:"1" 2:"0" 1:"1" 0:"1" +}} + +{{#bits 8 > + "ldh [c], a" 7:"1" 6:"1" 5:"1" 4:"0" 3:"0" 2:"1" 1:"0" 0:"0" ; + "ldh [imm8], a" 7:"1" 6:"1" 5:"1" 4:"0" 3:"0" 2:"0" 1:"0" 0:"0" ; + "ld [imm16], a" 7:"1" 6:"1" 5:"1" 4:"0" 3:"1" 2:"1" 1:"0" 0:"0" ; + "ldh a, [c]" 7:"1" 6:"1" 5:"1" 4:"1" 3:"0" 2:"1" 1:"0" 0:"0" ; + "ldh a, [imm8]" 7:"1" 6:"1" 5:"1" 4:"1" 3:"0" 2:"0" 1:"0" 0:"0" ; + "ld a, [imm16]" 7:"1" 6:"1" 5:"1" 4:"1" 3:"1" 2:"1" 1:"0" 0:"0" ; +}} + +{{#bits 8 > + "add sp, imm8" 7:"1" 6:"1" 5:"1" 4:"0" 3:"1" 2:"0" 1:"0" 0:"0" ; + "ld hl, sp + imm8" 7:"1" 6:"1" 5:"1" 4:"1" 3:"1" 2:"0" 1:"0" 0:"0" ; + "ld sp, hl" 7:"1" 6:"1" 5:"1" 4:"1" 3:"1" 2:"0" 1:"0" 0:"1" ; +}} + +{{#bits 8 > + "di" 7:"1" 6:"1" 5:"1" 4:"1" 3:"0" 2:"0" 1:"1" 0:"1" ; + "ei" 7:"1" 6:"1" 5:"1" 4:"1" 3:"1" 2:"0" 1:"1" 0:"1" ; +}} + +The following opcodes are **invalid**, and [hard-lock the CPU](https://gist.github.com/SonoSooS/c0055300670d678b5ae8433e20bea595#opcode-holes-not-implemented-opcodes) until the console is powered off: \$D3, \$DB, \$DD, \$E3, \$E4, \$EB, \$EC, \$ED, \$F4, \$FC, and \$FD. + +## \$CB prefix instructions + +{{#bits 8 > + "rlc r8" 7:"0" 6:"0" 5:"0" 4:"0" 3:"0" 2-0:"Operand (r8)" ; + "rrc r8" 7:"0" 6:"0" 5:"0" 4:"0" 3:"1" 2-0:"Operand (r8)" ; + "rl r8" 7:"0" 6:"0" 5:"0" 4:"1" 3:"0" 2-0:"Operand (r8)" ; + "rr r8" 7:"0" 6:"0" 5:"0" 4:"1" 3:"1" 2-0:"Operand (r8)" ; + "sla r8" 7:"0" 6:"0" 5:"1" 4:"0" 3:"0" 2-0:"Operand (r8)" ; + "sra r8" 7:"0" 6:"0" 5:"1" 4:"0" 3:"1" 2-0:"Operand (r8)" ; + "swap r8" 7:"0" 6:"0" 5:"1" 4:"1" 3:"0" 2-0:"Operand (r8)" ; + "srl r8" 7:"0" 6:"0" 5:"1" 4:"1" 3:"1" 2-0:"Operand (r8)" ; +}} + +{{#bits 8 > + "bit b3, r8" 7:"0" 6:"1" 5-3:"Bit index (b3)" 2-0:"Operand (r8)" ; + "res b3, r8" 7:"1" 6:"0" 5-3:"Bit index (b3)" 2-0:"Operand (r8)" ; + "set b3, r8" 7:"1" 6:"1" 5-3:"Bit index (b3)" 2-0:"Operand (r8)" ; +}}