--- # src: http://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html # src: http://www.devrs.com/gb/files/opcodes.html # TODO: DAA, see # http://datasheets.chipdb.org/Zilog/Z80/z80-documented-0.90.pdf # http://forums.nesdev.com/viewtopic.php?t=9088 ops: main: - id: NOP hex: 0x00 cat: misc op: NOP len: 1 pc: true time: 4 flags: z: n: h: c: code: | /* do nothing */ - id: LD BC, d16 hex: 0x01 cat: "16-bit load/store/move" op: LD dst: BC src: d16 len: 3 pc: true time: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_BC, mmu_rw(ctx, old_pc + 1)); - id: LD (BC), A hex: 0x02 cat: "8-bit load/store/move" op: LD dst: (BC) src: A len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_BC), cpu_rb(ctx, RB_A)); - id: INC BC hex: 0x03 cat: "16-bit math" op: INC dst: BC len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_BC, cpu_rw(ctx, RW_BC) + 1); - id: INC B hex: 0x04 cat: "8-bit math" op: INC dst: B len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: code: | inc_rb(ctx, RB_B); - id: DEC B hex: 0x05 cat: "8-bit math" op: DEC dst: B len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: code: | dec_rb(ctx, RB_B); - id: LD B, d8 hex: 0x06 cat: "8-bit load/store/move" op: LD dst: B src: d8 len: 2 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_B, mmu_rb(ctx, old_pc + 1)); - id: RLCA hex: 0x07 cat: "8-bit rotations/shifts" op: RLC dst: A len: 1 pc: true time: 4 flags: z: "0" n: "0" h: "0" c: C code: | rlc_rb(ctx, RB_A); - id: LD (a16), SP hex: 0x08 cat: "16-bit load/store/move" op: LD dst: (a16) src: SP len: 3 pc: true time: 20 flags: z: n: h: c: code: | mmu_ww(ctx, mmu_rw(ctx, old_pc + 1), cpu_rw(ctx, RW_SP)); - id: ADD HL, BC hex: 0x09 cat: "16-bit math" op: ADD dst: HL src: BC len: 1 pc: true time: 8 flags: z: n: "0" h: H c: C code: | add_rw_rw(ctx, RW_HL, RW_BC); - id: LD A, (BC) hex: 0x0A cat: "8-bit load/store/move" op: LD dst: A src: (BC) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, mmu_rb(ctx, cpu_rw(ctx, RW_BC))); - id: DEC BC hex: 0x0B cat: "16-bit math" op: DEC dst: BC len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_BC, cpu_rw(ctx, RW_BC) - 1); - id: INC C hex: 0x0C cat: "8-bit math" op: INC dst: C len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: code: inc_rb(ctx, RB_C); - id: DEC C hex: 0x0D cat: "8-bit math" op: DEC dst: C len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: code: | dec_rb(ctx, RB_C); - id: LD C, d8 hex: 0x0E cat: "8-bit load/store/move" op: LD dst: C src: d8 len: 2 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_C, mmu_rb(ctx, old_pc + 1)); - id: RRCA hex: 0x0F cat: "8-bit rotations/shifts" op: RRC dst: A len: 1 pc: true time: 4 flags: z: "0" n: "0" h: "0" c: C code: | rrc_rb(ctx, RB_A); - id: STOP hex: 0x10 cat: misc op: STOP len: 2 pc: false time: 4 flags: z: n: h: c: code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_STOP); - id: LD DE, d16 hex: 0x11 cat: "16-bit load/store/move" op: LD dst: DE src: d16 len: 3 pc: true time: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_DE, mmu_rw(ctx, old_pc + 1)); - id: LD (DE), A hex: 0x12 cat: "8-bit load/store/move" op: LD dst: (DE) src: A len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_DE), cpu_rb(ctx, RB_A)); - id: INC DE hex: 0x13 cat: "16-bit math" op: INC dst: DE len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_DE, cpu_rw(ctx, RW_DE) + 1); - id: INC D hex: 0x14 cat: "8-bit math" op: INC dst: D len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: code: | inc_rb(ctx, RB_D); - id: DEC D hex: 0x15 cat: "8-bit math" op: DEC dst: D len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: code: | dec_rb(ctx, RB_D); - id: LD D, d8 hex: 0x16 cat: "8-bit load/store/move" op: LD dst: D src: d8 len: 2 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_D, mmu_rb(ctx, old_pc + 1)); - id: RLA hex: 0x17 cat: "8-bit rotations/shifts" op: RL dst: A len: 1 pc: true time: 4 flags: z: "0" n: "0" h: "0" c: C code: | rl_rb(ctx, RB_A); - id: JR r8 hex: 0x18 cat: "jumps/calls" op: JR dst: PC src: r8 len: 2 pc: false time: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 2); jr(ctx, old_pc + 1); - id: ADD HL, DE hex: 0x19 cat: "16-bit math" op: ADD dst: HL src: DE len: 1 pc: true time: 8 flags: z: n: "0" h: H c: C code: | add_rw_rw(ctx, RW_HL, RW_DE); - id: LD A, (DE) hex: 0x1A cat: "8-bit load/store/move" op: LD dst: A src: (DE) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, mmu_rb(ctx, cpu_rw(ctx, RW_DE))); - id: DEC DE hex: 0x1B cat: "16-bit math" op: DEC dst: DE len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_BC, cpu_rw(ctx, RW_BC) - 1); - id: INC E hex: 0x1C cat: "8-bit math" op: INC dst: E len: 1 pc: true time: 4 flags: z: "Z" n: "0" h: H c: code: | inc_rb(ctx, RB_E); - id: DEC E hex: 0x1D cat: "8-bit math" op: DEC dst: E len: 1 pc: true time: 4 flags: z: "Z" n: "1" h: H c: code: | dec_rb(ctx, RB_E); - id: LD E, d8 hex: 0x1E cat: "8-bit load/store/move" op: LD dst: E src: d8 len: 2 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_E, mmu_rb(ctx, old_pc + 1)); - id: RRA hex: 0x1F cat: "8-bit rotations/shifts" op: RR dst: A len: 1 pc: true time: 4 flags: z: "0" n: "0" h: "0" c: C code: | rr_rb(ctx, RB_A); - id: JR NZ, r8 hex: 0x20 cat: "jumps/calls" op: JR test: NZ dst: PC src: F len: 2 pc: false time: t: 12 f: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 2); if (!FLAG(ctx, Z)) { jr(ctx, old_pc + 1); clock = 12; } - id: LD HL, d16 hex: 0x21 cat: "16-bit load/store/move" op: LD dst: HL src: d16 len: 3 pc: true time: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_HL, mmu_rw(ctx, old_pc + 1)); - id: LD (HL+), A hex: 0x22 cat: "8-bit load/store/move" op: LD dst: (HL+) src: A len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_A)); cpu_ww(ctx, RW_HL, cpu_rw(ctx, RW_HL) + 1); - id: INC HL hex: 0x23 cat: "16-bit math" op: INC dst: HL len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_HL, cpu_rw(ctx, RW_HL) + 1); - id: INC H hex: 0x24 cat: "8-bit math" op: INC dst: H len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: code: | inc_rb(ctx, RB_H); - id: DEC H hex: 0x25 cat: "8-bit math" op: DEC dst: H len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: code: | dec_rb(ctx, RB_H); - id: LD H, d8 hex: 0x26 cat: "8-bit load/store/move" op: LD dst: H src: d8 len: 2 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_E, mmu_rb(ctx, old_pc + 1)); - id: DAA hex: 0x27 cat: "8-bit math" op: DAA dst: A len: 1 pc: true time: 4 flags: z: Z n: h: "0" c: C code: | daa(ctx); - id: JR Z, r8 hex: 0x28 cat: "jumps/calls" op: JR test: Z dst: PC len: 2 pc: false time: t: 12 f: 8 flags: z: n: h: "0" c: C code: | cpu_ww(ctx, RW_PC, old_pc + 2); if (FLAG(ctx, Z)) { jr(ctx, old_pc + 1); clock = 12; } - id: ADD HL, HL hex: 0x29 cat: "16-bit math" op: ADD dst: HL src: HL len: 1 pc: true time: 8 flags: z: n: "0" h: H c: C code: | add_rw_rw(ctx, RW_HL, RW_HL); - id: LD A, (HL+) hex: 0x2A cat: "8-bit load/store/move" op: LD dst: A src: (HL+) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); cpu_ww(ctx, RW_HL, cpu_rw(ctx, RW_HL) + 1); - id: DEC HL hex: 0x2B cat: "16-bit math" op: DEC dst: HL len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_HL, cpu_rw(ctx, RW_HL) - 1); - id: INC L hex: 0x2C cat: "8-bit math" op: INC dst: L len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: code: | inc_rb(ctx, RB_L); - id: DEC L hex: 0x2D cat: "8-bit math" op: DEC dst: L len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: code: | dec_rb(ctx, RB_L); - id: LD L, d8 hex: 0x2E cat: "8-bit load/store/move" op: LD dst: L src: d8 len: 2 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_L, mmu_rb(ctx, old_pc + 1)); - id: CPL hex: 0x2F cat: "8-bit math" op: CPL src: d8 len: 1 pc: true time: 4 flags: z: n: "1" h: "1" c: code: | cpu_wb(ctx, RB_A, cpu_rb(ctx, RB_A) ^ 0xFF); cpu_wf(ctx, F_N | F_H, F_N | F_H); - id: JR NC, r8 hex: 0x30 cat: "jumps/calls" op: JR test: NC dst: PC len: 2 pc: false time: t: 12 f: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 2); if (!FLAG(ctx, C)) { jr(ctx, old_pc + 1); clock = 12; } - id: LD SP, d16 hex: 0x31 cat: "16-bit load/store/move" op: LD dst: SP src: d16 len: 3 pc: true time: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_SP, mmu_rw(ctx, old_pc + 1)); - id: LD (HL-), A hex: 0x32 cat: "8-bit load/store/move" op: LD dst: (HL-) src: A len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_A)); cpu_ww(ctx, RW_HL, cpu_rw(ctx, RW_HL) - 1); - id: INC SP hex: 0x33 cat: "16-bit math" op: INC dst: SP len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_SP, cpu_rw(ctx, RW_SP) + 1); - id: INC (HL) hex: 0x34 cat: "8-bit math" op: INC dst: (HL) len: 1 pc: true time: 12 flags: z: Z n: "0" h: H c: code: | inc_hl_ptr(ctx); - id: DEC (HL) hex: 0x35 cat: "8-bit math" op: DEC dst: (HL) len: 1 pc: true time: 12 flags: z: Z n: "1" h: H c: code: | dec_hl_ptr(ctx); - id: LD (HL), d8 hex: 0x36 cat: "8-bit load/store/move" op: LD dst: (HL) src: d8 len: 2 pc: true time: 12 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), mmu_rb(ctx, old_pc + 1)); - id: SCF hex: 0x37 cat: "8-bit math" op: SCF dst: F src: d8 len: 1 pc: true time: 4 flags: z: n: "0" h: "0" c: "1" code: | cpu_wf(ctx, F_N | F_H | F_C, F_C); - id: JR C, r8 hex: 0x38 cat: "jumps/calls" op: JR test: C dst: PC len: 2 pc: false time: t: 12 f: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 2); if (FLAG(ctx, C)) { jr(ctx, old_pc + 1); clock = 12; } - id: ADD HL, SP hex: 0x39 cat: "16-bit math" op: ADD dst: HL src: SP len: 1 pc: true time: 8 flags: z: n: "0" h: H c: C code: | add_rw_rw(ctx, RW_HL, RW_SP); - id: LD A, (HL-) hex: 0x3A cat: "8-bit load/store/move" op: LD dst: A src: (HL-) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); cpu_ww(ctx, RW_HL, cpu_rw(ctx, RW_HL) - 1); - id: DEC SP hex: 0x3B cat: "16-bit math" op: DEC dst: SP len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_SP, cpu_rw(ctx, RW_SP) - 1); - id: INC A hex: 0x3C cat: "8-bit math" op: INC dst: A len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: code: | inc_rb(ctx, RB_A); - id: DEC A hex: 0x3D cat: "8-bit math" op: DEC dst: A len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: code: | dec_rb(ctx, RB_A); - id: LD A, d8 hex: 0x3E cat: "8-bit load/store/move" op: LD dst: A src: d8 len: 2 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, mmu_rb(ctx, old_pc + 1)); - id: CCF hex: 0x3F cat: "8-bit math" op: CCF dst: F len: 1 pc: true time: 4 flags: z: n: "0" h: "0" c: C code: | cpu_wf(ctx, F_N | F_H | F_C, FLAG(ctx, C) ? 0 : F_C); - id: LD B, B hex: 0x40 cat: "8-bit load/store/move" op: LD dst: B src: B len: 1 pc: true time: 4 flags: z: n: h: c: code: | // do nothing - id: LD B, C hex: 0x41 cat: "8-bit load/store/move" op: LD dst: B src: C len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_B, cpu_rb(ctx, RB_C)); - id: LD B, D hex: 0x42 cat: "8-bit load/store/move" op: LD dst: B src: D len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_B, cpu_rb(ctx, RB_D)); - id: LD B, E hex: 0x43 cat: "8-bit load/store/move" op: LD dst: B src: E len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_B, cpu_rb(ctx, RB_E)); - id: LD B, H hex: 0x44 cat: "8-bit load/store/move" op: LD dst: B src: H len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_B, cpu_rb(ctx, RB_H)); - id: LD B, L hex: 0x45 cat: "8-bit load/store/move" op: LD dst: B src: L len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_B, cpu_rb(ctx, RB_L)); - id: LD B, (HL) hex: 0x46 cat: "8-bit load/store/move" op: LD dst: B src: (HL) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_B, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); - id: LD B, A hex: 0x47 cat: "8-bit load/store/move" op: LD dst: B src: A len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_B, cpu_rb(ctx, RB_A)); - id: LD C, B hex: 0x48 cat: "8-bit load/store/move" op: LD dst: C src: B len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_C, cpu_rb(ctx, RB_B)); - id: LD C, C hex: 0x49 cat: "8-bit load/store/move" op: LD dst: C src: C len: 1 pc: true time: 4 flags: z: n: h: c: code: | // do nothing - id: LD C, D hex: 0x4A cat: "8-bit load/store/move" op: LD dst: C src: D len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_C, cpu_rb(ctx, RB_D)); - id: LD C, E hex: 0x4B cat: "8-bit load/store/move" op: LD dst: C src: E len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_C, cpu_rb(ctx, RB_E)); - id: LD C, H hex: 0x4C cat: "8-bit load/store/move" op: LD dst: C src: H len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_C, cpu_rb(ctx, RB_H)); - id: LD C, L hex: 0x4D cat: "8-bit load/store/move" op: LD dst: C src: L len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_C, cpu_rb(ctx, RB_L)); - id: LD C, (HL) hex: 0x4E cat: "8-bit load/store/move" op: LD dst: C src: (HL) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_C, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); - id: LD C, A hex: 0x4F cat: "8-bit load/store/move" op: LD dst: C src: A len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_C, cpu_rb(ctx, RB_A)); - id: LD D, B hex: 0x50 cat: "8-bit load/store/move" op: LD dst: D src: B len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_D, cpu_rb(ctx, RB_B)); - id: LD D, C hex: 0x51 cat: "8-bit load/store/move" op: LD dst: D src: C len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_D, cpu_rb(ctx, RB_C)); - id: LD D, D hex: 0x52 cat: "8-bit load/store/move" op: LD dst: D src: D len: 1 pc: true time: 4 flags: z: n: h: c: code: | // do nothing - id: LD D, E hex: 0x53 cat: "8-bit load/store/move" op: LD dst: D src: E len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_D, cpu_rb(ctx, RB_E)); - id: LD D, H hex: 0x54 cat: "8-bit load/store/move" op: LD dst: D src: H len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_D, cpu_rb(ctx, RB_H)); - id: LD D, L hex: 0x55 cat: "8-bit load/store/move" op: LD dst: D src: L len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_D, cpu_rb(ctx, RB_L)); - id: LD D, (HL) hex: 0x56 cat: "8-bit load/store/move" op: LD dst: D src: (HL) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_D, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); - id: LD D, A hex: 0x57 cat: "8-bit load/store/move" op: LD dst: D src: A len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_D, cpu_rb(ctx, RB_A)); - id: LD E, B hex: 0x58 cat: "8-bit load/store/move" op: LD dst: E src: B len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_E, cpu_rb(ctx, RB_B)); - id: LD E, C hex: 0x59 cat: "8-bit load/store/move" op: LD dst: E src: C len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_E, cpu_rb(ctx, RB_C)); - id: LD E, D hex: 0x5A cat: "8-bit load/store/move" op: LD dst: E src: D len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_E, cpu_rb(ctx, RB_D)); - id: LD E, E hex: 0x5B cat: "8-bit load/store/move" op: LD dst: E src: E len: 1 pc: true time: 4 flags: z: n: h: c: code: | // do nothing - id: LD E, H hex: 0x5C cat: "8-bit load/store/move" op: LD dst: E src: H len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_E, cpu_rb(ctx, RB_H)); - id: LD E, L hex: 0x5D cat: "8-bit load/store/move" op: LD dst: E src: L len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_E, cpu_rb(ctx, RB_L)); - id: LD E, (HL) hex: 0x5E cat: "8-bit load/store/move" op: LD dst: E src: (HL) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_E, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); - id: LD E, A hex: 0x5F cat: "8-bit load/store/move" op: LD dst: E src: A len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_E, cpu_rb(ctx, RB_A)); - id: LD H, B hex: 0x60 cat: "8-bit load/store/move" op: LD dst: H src: B len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_H, cpu_rb(ctx, RB_B)); - id: LD H, C hex: 0x61 cat: "8-bit load/store/move" op: LD dst: H src: C len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_H, cpu_rb(ctx, RB_C)); - id: LD H, D hex: 0x62 cat: "8-bit load/store/move" op: LD dst: H src: D len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_H, cpu_rb(ctx, RB_D)); - id: LD H, E hex: 0x63 cat: "8-bit load/store/move" op: LD dst: H src: E len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_H, cpu_rb(ctx, RB_E)); - id: LD H, H hex: 0x64 cat: "8-bit load/store/move" op: LD dst: H src: H len: 1 pc: true time: 4 flags: z: n: h: c: code: | // do nothing - id: LD H, L hex: 0x65 cat: "8-bit load/store/move" op: LD dst: H src: L len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_H, cpu_rb(ctx, RB_L)); - id: LD H, (HL) hex: 0x66 cat: "8-bit load/store/move" op: LD dst: H src: (HL) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_H, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); - id: LD H, A hex: 0x67 cat: "8-bit load/store/move" op: LD dst: H src: A len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_H, cpu_rb(ctx, RB_A)); - id: LD L, B hex: 0x68 cat: "8-bit load/store/move" op: LD dst: L src: B len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_L, cpu_rb(ctx, RB_B)); - id: LD L, C hex: 0x69 cat: "8-bit load/store/move" op: LD dst: L src: C len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_L, cpu_rb(ctx, RB_C)); - id: LD L, D hex: 0x6A cat: "8-bit load/store/move" op: LD dst: L src: D len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_L, cpu_rb(ctx, RB_D)); - id: LD L, E hex: 0x6B cat: "8-bit load/store/move" op: LD dst: L src: E len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_L, cpu_rb(ctx, RB_E)); - id: LD L, H hex: 0x6C cat: "8-bit load/store/move" op: LD dst: L src: H len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_L, cpu_rb(ctx, RB_H)); - id: LD L, L hex: 0x6D cat: "8-bit load/store/move" op: LD dst: L src: L len: 1 pc: true time: 4 flags: z: n: h: c: code: | // do nothing - id: LD L, (HL) hex: 0x6E cat: "8-bit load/store/move" op: LD dst: L src: (HL) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_L, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); - id: LD L, A hex: 0x6F cat: "8-bit load/store/move" op: LD dst: L src: A len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_L, cpu_rb(ctx, RB_A)); - id: LD (HL), B hex: 0x70 cat: "8-bit load/store/move" op: LD dst: (HL) src: B len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_B)); - id: LD (HL), C hex: 0x71 cat: "8-bit load/store/move" op: LD dst: (HL) src: C len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_C)); - id: LD (HL), D hex: 0x72 cat: "8-bit load/store/move" op: LD dst: (HL) src: D len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_D)); - id: LD (HL), E hex: 0x73 cat: "8-bit load/store/move" op: LD dst: (HL) src: E len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_E)); - id: LD (HL), H hex: 0x74 cat: "8-bit load/store/move" op: LD dst: (HL) src: H len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_H)); - id: LD (HL), L hex: 0x75 cat: "8-bit load/store/move" op: LD dst: (HL) src: L len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_L)); - id: HALT hex: 0x76 cat: misc op: HALT len: 1 pc: false time: 4 flags: z: n: h: c: code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_HALT); - id: LD (HL), A hex: 0x77 cat: "8-bit load/store/move" op: LD dst: (HL) src: A len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_A)); - id: LD A, B hex: 0x78 cat: "8-bit load/store/move" op: LD dst: A src: B len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, cpu_rb(ctx, RB_B)); - id: LD A, C hex: 0x79 cat: "8-bit load/store/move" op: LD dst: A src: C len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, cpu_rb(ctx, RB_C)); - id: LD A, D hex: 0x7A cat: "8-bit load/store/move" op: LD dst: A src: D len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, cpu_rb(ctx, RB_D)); - id: LD A, E hex: 0x7B cat: "8-bit load/store/move" op: LD dst: A src: E len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, cpu_rb(ctx, RB_E)); - id: LD A, H hex: 0x7C cat: "8-bit load/store/move" op: LD dst: A src: H len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, cpu_rb(ctx, RB_H)); - id: LD A, L hex: 0x7D cat: "8-bit load/store/move" op: LD dst: A src: L len: 1 pc: true time: 4 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, cpu_rb(ctx, RB_L)); - id: LD A, (HL) hex: 0x7E cat: "8-bit load/store/move" op: LD dst: A src: (HL) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); - id: LD A, A hex: 0x7F cat: "8-bit load/store/move" op: LD dst: A src: A len: 1 pc: true time: 4 flags: z: n: h: c: code: | // do nothing - id: ADD A, B hex: 0x80 cat: "8-bit math" op: ADD dst: A src: B len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | add_rb(ctx, RB_B); - id: ADD A, C hex: 0x81 cat: "8-bit math" op: ADD dst: A src: C len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | add_rb(ctx, RB_C); - id: ADD A, D hex: 0x82 cat: "8-bit math" op: ADD dst: A src: D len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | add_rb(ctx, RB_D); - id: ADD A, E hex: 0x83 cat: "8-bit math" op: ADD dst: A src: E len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | add_rb(ctx, RB_E); - id: ADD A, H hex: 0x84 cat: "8-bit math" op: ADD dst: A src: H len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | add_rb(ctx, RB_H); - id: ADD A, L hex: 0x85 cat: "8-bit math" op: ADD dst: A src: L len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | add_rb(ctx, RB_L); - id: ADD A, (HL) hex: 0x86 cat: "8-bit math" op: ADD dst: A src: (HL) len: 1 pc: true time: 8 flags: z: Z n: "0" h: H c: C code: | add_hl_ptr(ctx); - id: ADD A, A hex: 0x87 cat: "8-bit math" op: ADD dst: A src: A len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | add_rb(ctx, RB_A); - id: ADC A, B hex: 0x88 cat: "8-bit math" op: ADC dst: A src: B len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | adc_rb(ctx, RB_B); - id: ADC A, C hex: 0x89 cat: "8-bit math" op: ADC dst: A src: C len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | adc_rb(ctx, RB_C); - id: ADC A, D hex: 0x8A cat: "8-bit math" op: ADC dst: A src: D len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | adc_rb(ctx, RB_D); - id: ADC A, E hex: 0x8B cat: "8-bit math" op: ADC dst: A src: E len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | adc_rb(ctx, RB_E); - id: ADC A, H hex: 0x8C cat: "8-bit math" op: ADC dst: A src: H len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | adc_rb(ctx, RB_H); - id: ADC A, L hex: 0x8D cat: "8-bit math" op: ADC dst: A src: L len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | adc_rb(ctx, RB_L); - id: ADC A, (HL) hex: 0x8E cat: "8-bit math" op: ADC dst: A src: (HL) len: 1 pc: true time: 8 flags: z: Z n: "0" h: H c: C code: | adc_hl_ptr(ctx); - id: ADC A, A hex: 0x8F cat: "8-bit math" op: ADC dst: A src: A len: 1 pc: true time: 4 flags: z: Z n: "0" h: H c: C code: | adc_rb(ctx, RB_A); - id: SUB B hex: 0x90 cat: "8-bit math" op: SUB dst: A src: B len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sub_rb(ctx, RB_B); - id: SUB C hex: 0x91 cat: "8-bit math" op: SUB dst: A src: C len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sub_rb(ctx, RB_C); - id: SUB D hex: 0x92 cat: "8-bit math" op: SUB dst: A src: D len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sub_rb(ctx, RB_D); - id: SUB E hex: 0x93 cat: "8-bit math" op: SUB dst: A src: E len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sub_rb(ctx, RB_E); - id: SUB H hex: 0x94 cat: "8-bit math" op: SUB dst: A src: H len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sub_rb(ctx, RB_H); - id: SUB L hex: 0x95 cat: "8-bit math" op: SUB dst: A src: L len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sub_rb(ctx, RB_L); - id: SUB (HL) hex: 0x96 cat: "8-bit math" op: SUB dst: A src: (HL) len: 1 pc: true time: 8 flags: z: Z n: "1" h: H c: C code: | sub_hl_ptr(ctx); - id: SUB A hex: 0x97 cat: "8-bit math" op: SUB dst: A src: A len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sub_rb(ctx, RB_A); - id: SBC A, B hex: 0x98 cat: "8-bit math" op: SBC dst: A src: B len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sbc_rb(ctx, RB_B); - id: SBC A, C hex: 0x99 cat: "8-bit math" op: SBC dst: A src: C len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sbc_rb(ctx, RB_C); - id: SBC A, D hex: 0x9A cat: "8-bit math" op: SBC dst: A src: D len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sbc_rb(ctx, RB_D); - id: SBC A, E hex: 0x9B cat: "8-bit math" op: SBC dst: A src: E len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sbc_rb(ctx, RB_E); - id: SBC A, H hex: 0x9C cat: "8-bit math" op: SBC dst: A src: H len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sbc_rb(ctx, RB_H); - id: SBC A, L hex: 0x9D cat: "8-bit math" op: SBC dst: A src: L len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sbc_rb(ctx, RB_L); - id: SBC A, (HL) hex: 0x9E cat: "8-bit math" op: SBC dst: A src: (HL) len: 1 pc: true time: 8 flags: z: Z n: "1" h: H c: C code: | sbc_hl_ptr(ctx); - id: SBC A, A hex: 0x9F cat: "8-bit math" op: SBC dst: A src: A len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | sbc_rb(ctx, RB_A); - id: AND B hex: 0xA0 cat: "8-bit math" op: AND src: B len: 1 pc: true time: 4 flags: z: Z n: "0" h: "1" c: "0" code: | and_rb(ctx, RB_B); - id: AND C hex: 0xA1 cat: "8-bit math" op: AND src: C len: 1 pc: true time: 4 flags: z: Z n: "0" h: "1" c: "0" code: | and_rb(ctx, RB_C); - id: AND D hex: 0xA2 cat: "8-bit math" op: AND src: D len: 1 pc: true time: 4 flags: z: Z n: "0" h: "1" c: "0" code: | and_rb(ctx, RB_D); - id: AND E hex: 0xA3 cat: "8-bit math" op: AND src: E len: 1 pc: true time: 4 flags: z: Z n: "0" h: "1" c: "0" code: | and_rb(ctx, RB_E); - id: AND H hex: 0xA4 cat: "8-bit math" op: AND src: H len: 1 pc: true time: 4 flags: z: Z n: "0" h: "1" c: "0" code: | and_rb(ctx, RB_H); - id: AND L hex: 0xA5 cat: "8-bit math" op: AND src: L len: 1 pc: true time: 4 flags: z: Z n: "0" h: "1" c: "0" code: | and_rb(ctx, RB_L); - id: AND (HL) hex: 0xA6 cat: "8-bit math" op: AND src: (HL) len: 1 pc: true time: 8 flags: z: Z n: "0" h: "1" c: "0" code: | and_hl_ptr(ctx); - id: AND A hex: 0xA7 cat: "8-bit math" op: AND src: A len: 1 pc: true time: 4 flags: z: Z n: "0" h: "1" c: "0" code: | and_rb(ctx, RB_A); - id: XOR B hex: 0xA8 cat: "8-bit math" op: XOR src: B len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | xor_rb(ctx, RB_B); - id: XOR C hex: 0xA9 cat: "8-bit math" op: XOR src: C len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | xor_rb(ctx, RB_C); - id: XOR D hex: 0xAA cat: "8-bit math" op: XOR src: D len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | xor_rb(ctx, RB_D); - id: XOR E hex: 0xAB cat: "8-bit math" op: XOR src: E len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | xor_rb(ctx, RB_E); - id: XOR H hex: 0xAC cat: "8-bit math" op: XOR src: H len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | xor_rb(ctx, RB_H); - id: XOR L hex: 0xAD cat: "8-bit math" op: XOR src: L len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | xor_rb(ctx, RB_L); - id: XOR (HL) hex: 0xAE cat: "8-bit math" op: XOR src: (HL) len: 1 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | xor_hl_ptr(ctx); - id: XOR A hex: 0xAF cat: "8-bit math" op: XOR src: A len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | xor_rb(ctx, RB_A); - id: OR B hex: 0xB0 cat: "8-bit math" op: OR src: B len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | or_rb(ctx, RB_B); - id: OR C hex: 0xB1 cat: "8-bit math" op: OR src: C len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | or_rb(ctx, RB_C); - id: OR D hex: 0xB2 cat: "8-bit math" op: OR src: D len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | or_rb(ctx, RB_D); - id: OR E hex: 0xB3 cat: "8-bit math" op: OR src: E len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | or_rb(ctx, RB_E); - id: OR H hex: 0xB4 cat: "8-bit math" op: OR src: H len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | or_rb(ctx, RB_H); - id: OR L hex: 0xB5 cat: "8-bit math" op: OR src: L len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | or_rb(ctx, RB_L); - id: OR (HL) hex: 0xB6 cat: "8-bit math" op: OR src: (HL) len: 1 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | or_hl_ptr(ctx); - id: OR A hex: 0xB7 cat: "8-bit math" op: OR src: A len: 1 pc: true time: 4 flags: z: Z n: "0" h: "0" c: "0" code: | or_rb(ctx, RB_A); - id: CP B hex: 0xB8 cat: "8-bit math" op: CP dst: A src: B len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | cp_rb(ctx, RB_B); - id: CP C hex: 0xB9 cat: "8-bit math" op: CP dst: A src: C len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | cp_rb(ctx, RB_C); - id: CP D hex: 0xBA cat: "8-bit math" op: CP dst: A src: D len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | cp_rb(ctx, RB_D); - id: CP E hex: 0xBB cat: "8-bit math" op: CP dst: A src: E len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | cp_rb(ctx, RB_E); - id: CP H hex: 0xBC cat: "8-bit math" op: CP dst: A src: H len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | cp_rb(ctx, RB_H); - id: CP L hex: 0xBD cat: "8-bit math" op: CP dst: A src: L len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | cp_rb(ctx, RB_L); - id: CP (HL) hex: 0xBE cat: "8-bit math" op: CP dst: A src: (HL) len: 1 pc: true time: 8 flags: z: Z n: "1" h: H c: C code: | cp_hl_ptr(ctx); - id: CP A hex: 0xBF cat: "8-bit math" op: CP dst: A src: A len: 1 pc: true time: 4 flags: z: Z n: "1" h: H c: C code: | cp_rb(ctx, RB_A); - id: RET NZ hex: 0xC0 cat: "jumps/calls" op: RET test: NZ dst: PC src: SP len: 1 pc: false time: t: 20 f: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); if (!FLAG(ctx, Z)) { pop_rw(ctx, RW_PC); clock = 20; } - id: POP BC hex: 0xC1 cat: "16-bit load/store/move" op: POP dst: BC src: SP len: 1 pc: true time: 12 flags: z: n: h: c: code: | pop_rw(ctx, RW_BC); - id: JP NZ, a16 hex: 0xC2 cat: "jumps/calls" op: JP test: NZ dst: PC src: a16 len: 3 pc: false time: t: 16 f: 32 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 3); if (!FLAG(ctx, Z)) { cpu_ww(ctx, RW_PC, mmu_rw(ctx, old_pc + 1)); clock = 16; } - id: JP a16 hex: 0xC3 cat: "jumps/calls" op: JP dst: PC src: a16 len: 3 pc: false time: 16 flags: z: n: h: c: code: | // unconditional jump cpu_ww(ctx, RW_PC, mmu_rw(ctx, old_pc + 1)); - id: CALL NZ, a16 hex: 0xC4 cat: "jumps/calls" op: CALL test: NZ dst: PC src: a16 len: 3 pc: false time: t: 24 f: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 3); if (!FLAG(ctx, Z)) { call_a16(ctx, old_pc + 1); clock = 24; } - id: PUSH BC hex: 0xC5 cat: "16-bit load/store/move" op: PUSH dst: SP src: BC len: 1 pc: true time: 16 flags: z: n: h: c: code: | push_rw(ctx, RW_BC); - id: ADD A, d8 hex: 0xC6 cat: "8-bit math" op: ADD dst: A src: d8 len: 2 pc: true time: 8 flags: z: Z n: "0" h: H c: C code: | add_d8(ctx, old_pc + 1); - id: RST 00H hex: 0xC7 cat: "jumps/calls" op: RST dst: PC addr: "0x00" len: 1 pc: false time: 16 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x00); - id: RET Z hex: 0xC8 cat: "jumps/calls" op: RET test: Z dst: PC src: SP len: 1 pc: false time: t: 20 f: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); if (FLAG(ctx, Z)) { pop_rw(ctx, RW_PC); clock += 20; } - id: RET hex: 0xC9 cat: "jumps/calls" op: RET dst: PC src: SP len: 1 pc: false time: 16 flags: z: n: h: c: code: | // pop pc pop_rw(ctx, RW_PC); - id: JP Z, a16 hex: 0xCA cat: "jumps/calls" op: JP test: Z dst: PC src: a16 len: 3 pc: false time: t: 16 f: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 3); if (FLAG(ctx, Z)) { cpu_ww(ctx, RW_PC, mmu_rw(ctx, old_pc + 1)); clock = 16; } - id: PREFIX CB hex: 0xCB cat: misc op: PREFIX len: 1 pc: false time: 4 flags: z: n: h: c: - id: CALL Z, a16 hex: 0xCC cat: "jumps/calls" op: CALL test: Z len: 3 pc: false time: t: 24 f: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 3); if (FLAG(ctx, Z)) { call_a16(ctx, old_pc + 1); clock = 24; } - id: CALL a16 hex: 0xCD cat: "jumps/calls" op: CALL len: 3 pc: false time: 24 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 3); call_a16(ctx, old_pc + 1); - id: ADC A, d8 hex: 0xCE cat: "8-bit math" op: ADC dst: A src: d8 len: 2 pc: true time: 8 flags: z: Z n: "0" h: H c: C code: | adc_d8(ctx, old_pc + 1); - id: RST 08H hex: 0xCF cat: "jumps/calls" op: RST len: 1 pc: false addr: "0x08" time: 16 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x08); - id: RET NC hex: 0xD0 cat: "jumps/calls" op: RET test: NC dst: PC src: SP len: 1 pc: false time: t: 20 f: 8 code: | cpu_ww(ctx, RW_PC, old_pc + 1); if (!FLAG(ctx, C)) { pop_rw(ctx, RW_PC); clock = 20; } flags: z: n: h: c: - id: POP DE hex: 0xD1 cat: "16-bit load/store/move" op: POP dst: DE src: SP len: 1 pc: true time: 12 flags: z: n: h: c: code: | // pop de pop_rw(ctx, RW_DE); - id: JP NC, a16 hex: 0xD2 cat: "jumps/calls" op: JP test: NC dst: PC src: a16 len: 3 pc: false time: t: 16 f: 32 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 3); if (!FLAG(ctx, C)) { cpu_ww(ctx, RW_PC, mmu_rw(ctx, old_pc + 1)); clock = 16; } - id: XX hex: 0xD3 cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: CALL NC, a16 hex: 0xD4 cat: "jumps/calls" op: CALL test: NC dst: PC src: a16 len: 3 pc: false time: t: 24 f: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 3); if (!FLAG(ctx, C)) { call_a16(ctx, old_pc + 1); clock = 24; } - id: PUSH DE hex: 0xD5 cat: "16-bit load/store/move" op: PUSH dst: SP src: DE len: 1 pc: true time: 16 flags: z: n: h: c: code: | push_rw(ctx, RW_DE); - id: SUB d8 hex: 0xD6 cat: "8-bit math" op: SUB dst: A src: d8 len: 2 pc: true time: 8 flags: z: Z n: "1" h: H c: C code: | sub_d8(ctx, old_pc + 1); - id: RST 10H hex: 0xD7 cat: "jumps/calls" op: RST dst: PC addr: "0x10" len: 1 pc: false time: 16 flags: z: Z n: "1" h: H c: C code: | cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x10); - id: RET C hex: 0xD8 cat: "jumps/calls" op: RET test: C dst: PC len: 1 pc: false time: t: 20 f: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); if (FLAG(ctx, C)) { pop_rw(ctx, RW_PC); clock += 20; } - id: RETI hex: 0xD9 cat: "jumps/calls" op: RETI dst: PC src: SP len: 1 pc: false time: 16 flags: z: n: h: c: code: | // pop pc, enable interrupts ctx->cpu.ime = true; pop_rw(ctx, RW_PC); - id: JP C, a16 hex: 0xDA cat: "jumps/calls" op: JP test: C dst: PC src: a16 len: 3 pc: false time: t: 16 f: 32 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 3); if (FLAG(ctx, C)) { cpu_ww(ctx, RW_PC, mmu_rw(ctx, old_pc + 1)); clock = 16; } - id: XX hex: 0xDB cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: CALL C, a16 hex: 0xDC cat: "jumps/calls" op: CALL test: C dst: PC src: a16 len: 3 pc: false time: t: 24 f: 12 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 3); if (FLAG(ctx, C)) { call_a16(ctx, old_pc + 1); clock = 24; } - id: XX hex: 0xDD cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: SBC A, d8 hex: 0xDE cat: "8-bit math" op: SBC dst: A src: d8 len: 2 pc: true time: 8 flags: z: Z n: "1" h: H c: C code: | sbc_d8(ctx, old_pc + 1); - id: RST 18H hex: 0xDF cat: "jumps/calls" op: RST dst: PC addr: "0x18" len: 1 pc: false time: 16 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x18); - id: LDH (a8), A hex: 0xE0 cat: "8-bit load/store/move" op: LDH dst: (a8) src: A len: 2 pc: true time: 12 flags: z: n: h: c: code: | mmu_wb(ctx, 0xFF00 + mmu_rb(ctx, old_pc + 1), cpu_rb(ctx, RB_A)); - id: POP HL hex: 0xE1 cat: "16-bit load/store/move" op: POP dst: HL src: SP len: 1 pc: true time: 12 flags: z: n: h: c: code: | pop_rw(ctx, RW_HL); - id: LD (C), A hex: 0xE2 cat: "8-bit load/store/move" op: LD dst: (C) src: A len: 1 pc: true time: 8 flags: z: n: h: c: code: | mmu_wb(ctx, 0xFF00 + cpu_rb(ctx, RB_C), cpu_rb(ctx, RB_A)); - id: XX hex: 0xE3 cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: XX hex: 0xE4 cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: PUSH HL hex: 0xE5 cat: "16-bit load/store/move" op: PUSH dst: SP src: HL len: 1 pc: true time: 16 flags: z: n: h: c: code: | push_rw(ctx, RW_HL); - id: AND d8 hex: 0xE6 cat: "8-bit math" op: AND src: d8 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: "0" code: | and_d8(ctx, old_pc + 1); - id: RST 20H hex: 0xE7 cat: "jumps/calls" op: RST dst: PC addr: "0x20" len: 1 pc: false time: 16 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x20); - id: ADD SP, r8 hex: 0xE8 cat: "misc" op: ADD dst: SP src: r8 len: 2 pc: true time: 16 flags: z: "0" n: "0" h: H c: C code: | add_sp_r8(ctx, old_pc + 1); - id: JP (HL) hex: 0xE9 cat: "jumps/calls" op: JP dst: PC src: (HL) len: 1 pc: false time: 4 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_HL)); - id: LD (a16), A hex: 0xEA cat: "8-bit load/store/move" op: LD dst: (a16) src: A len: 3 pc: true time: 16 flags: z: n: h: c: code: | mmu_wb(ctx, mmu_rw(ctx, old_pc + 1), cpu_rb(ctx, RB_A)); - id: XX hex: 0xEB cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: XX hex: 0xEC cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: XX hex: 0xED cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: XOR d8 hex: 0xEE cat: "8-bit math" op: XOR src: d8 len: 2 pc: true time: 8 flags: z: Z n: h: c: code: | xor_d8(ctx, old_pc + 1); - id: RST 28H hex: 0xEF cat: "jumps/calls" op: RST len: 1 pc: false addr: "0x28" time: 16 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x28); - id: LDH A, (a8) hex: 0xF0 cat: "8-bit load/store/move" op: LDH dst: A src: (a8) len: 2 pc: true time: 12 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, mmu_rb(ctx, 0xFF00 + mmu_rb(ctx, old_pc + 1))); - id: POP AF hex: 0xF1 cat: "16-bit load/store/move" op: POP dst: AF src: SP len: 1 pc: true time: 12 flags: z: Z n: N h: H c: C code: | pop_rw(ctx, RW_AF); - id: LD A, (C) hex: 0xF2 cat: "8-bit load/store/move" op: LD dst: A src: (C) len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, mmu_rb(ctx, 0xFF00 + cpu_rb(ctx, RB_C))); - id: DI hex: 0xF3 cat: "misc" op: DI len: 1 pc: true time: 4 flags: z: n: h: c: code: | // disable interrupts ctx->cpu.ime = false; - id: XX hex: 0xF4 cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: PUSH AF hex: 0xF5 cat: "16-bit load/store/move" op: PUSH dst: SP src: AF len: 1 pc: true time: 16 flags: z: n: h: c: code: | push_rw(ctx, RW_AF); - id: OR d8 hex: 0xF6 cat: "8-bit math" op: OR src: d8 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | or_d8(ctx, old_pc + 1); - id: RST 30H hex: 0xF7 cat: "jumps/calls" op: RST addr: "0x30" len: 1 pc: false time: 16 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x30); - id: LD HL, SP+r8 hex: 0xF8 cat: "16-bit load/store/move" op: LD dst: HL src: SP+r8 len: 2 pc: true time: 12 flags: z: "0" n: "0" h: H c: C code: | ld_hl_sp_r8(ctx, old_pc + 1); - id: LD SP, HL hex: 0xF9 cat: "16-bit load/store/move" op: LD dst: SP src: HL len: 1 pc: true time: 8 flags: z: n: h: c: code: | cpu_ww(ctx, RW_SP, cpu_rw(ctx, RW_HL)); - id: LD A, (a16) hex: 0xFA cat: "8-bit load/store/move" op: LD dst: A src: (a16) len: 3 pc: true time: 16 flags: z: n: h: c: code: | cpu_wb(ctx, RB_A, mmu_rb(ctx, mmu_rw(ctx, old_pc + 1))); - id: EI hex: 0xFB cat: "misc" op: EI len: 1 pc: true time: 4 flags: z: n: h: c: code: | // enable interrupts ctx->cpu.ime = true; - id: XX hex: 0xFC cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: XX hex: 0xFD cat: "invalid" op: XX code: | cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: CP d8 hex: 0xFE cat: "8-bit math" op: CP dst: A src: d8 len: 2 pc: true time: 8 flags: z: Z n: "1" h: H c: C code: | cp_d8(ctx, old_pc + 1); - id: RST 38H hex: 0xFF cat: "jumps/calls" op: RST dst: PC addr: "0x38" len: 1 pc: false time: 16 flags: z: n: h: c: code: | cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x38); cb: - id: RLC B hex: 0x00 cat: "8-bit rotations/shifts" op: RLC dst: B len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rlc_rb(ctx, RB_B); - id: RLC C hex: 0x01 cat: "8-bit rotations/shifts" op: RLC dst: C len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rlc_rb(ctx, RB_C); - id: RLC D hex: 0x02 cat: "8-bit rotations/shifts" op: RLC dst: D len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rlc_rb(ctx, RB_D); - id: RLC E hex: 0x03 cat: "8-bit rotations/shifts" op: RLC dst: E len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rlc_rb(ctx, RB_E); - id: RLC H hex: 0x04 cat: "8-bit rotations/shifts" op: RLC dst: H len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rlc_rb(ctx, RB_H); - id: RLC L hex: 0x05 cat: "8-bit rotations/shifts" op: RLC dst: L len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rlc_rb(ctx, RB_L); - id: RLC (HL) hex: 0x06 cat: "8-bit rotations/shifts" op: RLC dst: (HL) len: 2 pc: true time: 16 flags: z: Z n: "0" h: "0" c: C code: | rlc_hl(ctx); - id: RLC A hex: 0x07 cat: "8-bit rotations/shifts" op: RLC dst: A len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rlc_rb(ctx, RB_A); - id: RRC B hex: 0x08 cat: "8-bit rotations/shifts" op: RRC dst: B len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rrc_rb(ctx, RB_B); - id: RRC C hex: 0x09 cat: "8-bit rotations/shifts" op: RRC dst: C len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rrc_rb(ctx, RB_C); - id: RRC D hex: 0x0A cat: "8-bit rotations/shifts" op: RRC dst: D len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rrc_rb(ctx, RB_D); - id: RRC E hex: 0x0B cat: "8-bit rotations/shifts" op: RRC dst: E len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rrc_rb(ctx, RB_E); - id: RRC H hex: 0x0C cat: "8-bit rotations/shifts" op: RRC dst: H len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rrc_rb(ctx, RB_H); - id: RRC L hex: 0x0D cat: "8-bit rotations/shifts" op: RRC dst: L len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rrc_rb(ctx, RB_L); - id: RRC (HL) hex: 0x0E cat: "8-bit rotations/shifts" op: RRC dst: (HL) len: 2 pc: true time: 16 flags: z: Z n: "0" h: "0" c: C code: | rrc_hl_ptr(ctx); - id: RRC A hex: 0x0F cat: "8-bit rotations/shifts" op: RRC dst: A len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rrc_rb(ctx, RB_A); - id: RL B hex: 0x10 cat: "8-bit rotations/shifts" op: RL dst: B len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rl_rb(ctx, RB_B); - id: RL C hex: 0x11 cat: "8-bit rotations/shifts" op: RL dst: C len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rl_rb(ctx, RB_C); - id: RL D hex: 0x12 cat: "8-bit rotations/shifts" op: RL dst: D len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rl_rb(ctx, RB_D); - id: RL E hex: 0x13 cat: "8-bit rotations/shifts" op: RL dst: E len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rl_rb(ctx, RB_E); - id: RL H hex: 0x14 cat: "8-bit rotations/shifts" op: RL dst: H len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rl_rb(ctx, RB_H); - id: RL L hex: 0x15 cat: "8-bit rotations/shifts" op: RL dst: L len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rl_rb(ctx, RB_L); - id: RL (HL) hex: 0x16 cat: "8-bit rotations/shifts" op: RL dst: (HL) len: 2 pc: true time: 16 flags: z: Z n: "0" h: "0" c: C code: | rl_hl_ptr(ctx); - id: RL A hex: 0x17 cat: "8-bit rotations/shifts" op: RL dst: A len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rl_rb(ctx, RB_A); - id: RR B hex: 0x18 cat: "8-bit rotations/shifts" op: RR dst: B len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rr_rb(ctx, RB_B); - id: RR C hex: 0x19 cat: "8-bit rotations/shifts" op: RR dst: C len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rr_rb(ctx, RB_C); - id: RR D hex: 0x1A cat: "8-bit rotations/shifts" op: RR dst: D len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rr_rb(ctx, RB_D); - id: RR E hex: 0x1B cat: "8-bit rotations/shifts" op: RR dst: E len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rr_rb(ctx, RB_E); - id: RR H hex: 0x1C cat: "8-bit rotations/shifts" op: RR dst: H len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rr_rb(ctx, RB_H); - id: RR L hex: 0x1D cat: "8-bit rotations/shifts" op: RR dst: L len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rr_rb(ctx, RB_L); - id: RR (HL) hex: 0x1E cat: "8-bit rotations/shifts" op: RR dst: (HL) len: 2 pc: true time: 16 flags: z: Z n: "0" h: "0" c: C code: | rr_hl_ptr(ctx); - id: RR A hex: 0x1F cat: "8-bit rotations/shifts" op: RR dst: A len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | rr_rb(ctx, RB_A); - id: SLA B hex: 0x20 cat: "8-bit rotations/shifts" op: SLA dst: B len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | sla_rb(ctx, RB_B); - id: SLA C hex: 0x21 cat: "8-bit rotations/shifts" op: SLA dst: C len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | sla_rb(ctx, RB_C); - id: SLA D hex: 0x22 cat: "8-bit rotations/shifts" op: SLA dst: D len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | sla_rb(ctx, RB_D); - id: SLA E hex: 0x23 cat: "8-bit rotations/shifts" op: SLA dst: E len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | sla_rb(ctx, RB_E); - id: SLA H hex: 0x24 cat: "8-bit rotations/shifts" op: SLA dst: H len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | sla_rb(ctx, RB_H); - id: SLA L hex: 0x25 cat: "8-bit rotations/shifts" op: SLA dst: L len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | sla_rb(ctx, RB_L); - id: SLA (HL) hex: 0x26 cat: "8-bit rotations/shifts" op: SLA dst: (HL) len: 2 pc: true time: 16 flags: z: Z n: "0" h: "0" c: C code: | sla_hl_ptr(ctx); - id: SLA A hex: 0x27 cat: "8-bit rotations/shifts" op: SLA dst: A len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | sla_rb(ctx, RB_A); - id: SRA B hex: 0x28 cat: "8-bit rotations/shifts" op: SRA dst: B len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | sra_rb(ctx, RB_B); - id: SRA C hex: 0x29 cat: "8-bit rotations/shifts" op: SRA dst: C len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | sra_rb(ctx, RB_C); - id: SRA D hex: 0x2A cat: "8-bit rotations/shifts" op: SRA dst: D len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | sra_rb(ctx, RB_D); - id: SRA E hex: 0x2B cat: "8-bit rotations/shifts" op: SRA dst: E len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | sra_rb(ctx, RB_E); - id: SRA H hex: 0x2C cat: "8-bit rotations/shifts" op: SRA dst: H len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | sra_rb(ctx, RB_H); - id: SRA L hex: 0x2D cat: "8-bit rotations/shifts" op: SRA dst: L len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | sra_rb(ctx, RB_L); - id: SRA (HL) hex: 0x2E cat: "8-bit rotations/shifts" op: SRA dst: (HL) len: 2 pc: true time: 16 flags: z: Z n: "0" h: "0" c: "0" code: | sra_hl_ptr(ctx); - id: SRA A hex: 0x2F cat: "8-bit rotations/shifts" op: SRA dst: A len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | sra_rb(ctx, RB_A); - id: SWAP B hex: 0x30 cat: "8-bit rotations/shifts" op: SWAP dst: B len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | swap_rb(ctx, RB_B); - id: SWAP C hex: 0x31 cat: "8-bit rotations/shifts" op: SWAP dst: C len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | swap_rb(ctx, RB_C); - id: SWAP D hex: 0x32 cat: "8-bit rotations/shifts" op: SWAP dst: D len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | swap_rb(ctx, RB_D); - id: SWAP E hex: 0x33 cat: "8-bit rotations/shifts" op: SWAP dst: E len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | swap_rb(ctx, RB_E); - id: SWAP H hex: 0x34 cat: "8-bit rotations/shifts" op: SWAP dst: H len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | swap_rb(ctx, RB_H); - id: SWAP L hex: 0x35 cat: "8-bit rotations/shifts" op: SWAP dst: L len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | swap_rb(ctx, RB_L); - id: SWAP (HL) hex: 0x36 cat: "8-bit rotations/shifts" op: SWAP dst: (HL) len: 2 pc: true time: 16 flags: z: Z n: "0" h: "0" c: "0" code: | swap_hl_ptr(ctx); - id: SWAP A hex: 0x37 cat: "8-bit rotations/shifts" op: SWAP dst: A len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: "0" code: | swap_rb(ctx, RB_A); - id: SRL B hex: 0x38 cat: "8-bit rotations/shifts" op: SRL dst: B len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | srl_rb(ctx, RB_B); - id: SRL C hex: 0x39 cat: "8-bit rotations/shifts" op: SRL dst: C len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | srl_rb(ctx, RB_C); - id: SRL D hex: 0x3A cat: "8-bit rotations/shifts" op: SRL dst: D len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | srl_rb(ctx, RB_D); - id: SRL E hex: 0x3B cat: "8-bit rotations/shifts" op: SRL dst: E len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | srl_rb(ctx, RB_E); - id: SRL H hex: 0x3C cat: "8-bit rotations/shifts" op: SRL dst: H len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | srl_rb(ctx, RB_H); - id: SRL L hex: 0x3D cat: "8-bit rotations/shifts" op: SRL dst: L len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | srl_rb(ctx, RB_L); - id: SRL (HL) hex: 0x3E cat: "8-bit rotations/shifts" op: SRL dst: (HL) len: 2 pc: true time: 16 flags: z: Z n: "0" h: "0" c: C code: | srl_hl_ptr(ctx); - id: SRL A hex: 0x3F cat: "8-bit rotations/shifts" op: SRL dst: A len: 2 pc: true time: 8 flags: z: Z n: "0" h: "0" c: C code: | srl_rb(ctx, RB_A); - id: BIT 0, B hex: 0x40 cat: "8-bit rotations/shifts" op: BIT src: B bit: 0 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_B, 0); - id: BIT 0, C hex: 0x41 cat: "8-bit rotations/shifts" op: BIT src: C bit: 0 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_C, 0); - id: BIT 0, D hex: 0x42 cat: "8-bit rotations/shifts" op: BIT src: D bit: 0 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_D, 0); - id: BIT 0, E hex: 0x43 cat: "8-bit rotations/shifts" op: BIT src: E bit: 0 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_E, 0); - id: BIT 0, H hex: 0x44 cat: "8-bit rotations/shifts" op: BIT src: H bit: 0 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_H, 0); - id: BIT 0, L hex: 0x45 cat: "8-bit rotations/shifts" op: BIT src: L bit: 0 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_L, 0); - id: BIT 0, (HL) hex: 0x46 cat: "8-bit rotations/shifts" op: BIT src: (HL) bit: 0 len: 2 pc: true time: 16 flags: z: Z n: "0" h: "1" c: code: | bit_hl(ctx, 0); - id: BIT 0, A hex: 0x47 cat: "8-bit rotations/shifts" op: BIT src: A bit: 0 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_A, 0); - id: BIT 1, B hex: 0x48 cat: "8-bit rotations/shifts" op: BIT src: B bit: 1 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_B, 1); - id: BIT 1, C hex: 0x49 cat: "8-bit rotations/shifts" op: BIT src: C bit: 1 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_C, 1); - id: BIT 1, D hex: 0x4A cat: "8-bit rotations/shifts" op: BIT src: D bit: 1 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_D, 1); - id: BIT 1, E hex: 0x4B cat: "8-bit rotations/shifts" op: BIT src: E bit: 1 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_E, 1); - id: BIT 1, H hex: 0x4C cat: "8-bit rotations/shifts" op: BIT src: H bit: 1 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_H, 1); - id: BIT 1, L hex: 0x4D cat: "8-bit rotations/shifts" op: BIT src: L bit: 1 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_L, 1); - id: BIT 1, (HL) hex: 0x4E cat: "8-bit rotations/shifts" op: BIT src: (HL) bit: 1 len: 2 pc: true time: 16 flags: z: Z n: "0" h: "1" c: code: | bit_hl(ctx, 1); - id: BIT 1, A hex: 0x4F cat: "8-bit rotations/shifts" op: BIT src: A bit: 1 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_A, 1); - id: BIT 2, B hex: 0x50 cat: "8-bit rotations/shifts" op: BIT src: B bit: 2 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_B, 2); - id: BIT 2, C hex: 0x51 cat: "8-bit rotations/shifts" op: BIT src: C bit: 2 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_C, 2); - id: BIT 2, D hex: 0x52 cat: "8-bit rotations/shifts" op: BIT src: D bit: 2 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_D, 2); - id: BIT 2, E hex: 0x53 cat: "8-bit rotations/shifts" op: BIT src: E bit: 2 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_E, 2); - id: BIT 2, H hex: 0x54 cat: "8-bit rotations/shifts" op: BIT src: H bit: 2 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_H, 2); - id: BIT 2, L hex: 0x55 cat: "8-bit rotations/shifts" op: BIT src: L bit: 2 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_L, 2); - id: BIT 2, (HL) hex: 0x56 cat: "8-bit rotations/shifts" op: BIT src: (HL) bit: 2 len: 2 pc: true time: 16 flags: z: Z n: "0" h: "1" c: code: | bit_hl(ctx, 2); - id: BIT 2, A hex: 0x57 cat: "8-bit rotations/shifts" op: BIT src: A bit: 2 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_A, 2); - id: BIT 3, B hex: 0x58 cat: "8-bit rotations/shifts" op: BIT src: B bit: 3 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_B, 3); - id: BIT 3, C hex: 0x59 cat: "8-bit rotations/shifts" op: BIT src: C bit: 3 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_C, 3); - id: BIT 3, D hex: 0x5A cat: "8-bit rotations/shifts" op: BIT src: D bit: 3 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_D, 3); - id: BIT 3, E hex: 0x5B cat: "8-bit rotations/shifts" op: BIT src: E bit: 3 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_E, 3); - id: BIT 3, H hex: 0x5C cat: "8-bit rotations/shifts" op: BIT src: H bit: 3 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_H, 3); - id: BIT 3, L hex: 0x5D cat: "8-bit rotations/shifts" op: BIT src: L bit: 3 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_L, 3); - id: BIT 3, (HL) hex: 0x5E cat: "8-bit rotations/shifts" op: BIT src: (HL) bit: 3 len: 2 pc: true time: 16 flags: z: Z n: "0" h: "1" c: code: | bit_hl(ctx, 3); - id: BIT 3, A hex: 0x5F cat: "8-bit rotations/shifts" op: BIT src: A bit: 3 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_A, 3); - id: BIT 4, B hex: 0x60 cat: "8-bit rotations/shifts" op: BIT src: B bit: 4 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_B, 4); - id: BIT 4, C hex: 0x61 cat: "8-bit rotations/shifts" op: BIT src: C bit: 4 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_C, 4); - id: BIT 4, D hex: 0x62 cat: "8-bit rotations/shifts" op: BIT src: D bit: 4 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_D, 4); - id: BIT 4, E hex: 0x63 cat: "8-bit rotations/shifts" op: BIT src: E bit: 4 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_E, 4); - id: BIT 4, H hex: 0x64 cat: "8-bit rotations/shifts" op: BIT src: H bit: 4 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_H, 4); - id: BIT 4, L hex: 0x65 cat: "8-bit rotations/shifts" op: BIT src: L bit: 4 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_L, 4); - id: BIT 4, (HL) hex: 0x66 cat: "8-bit rotations/shifts" op: BIT src: (HL) bit: 4 len: 2 pc: true time: 16 flags: z: Z n: "0" h: "1" c: code: | bit_hl(ctx, 4); - id: BIT 4, A hex: 0x67 cat: "8-bit rotations/shifts" op: BIT src: A bit: 4 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_A, 4); - id: BIT 5, B hex: 0x68 cat: "8-bit rotations/shifts" op: BIT src: B bit: 5 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_B, 5); - id: BIT 5, C hex: 0x69 cat: "8-bit rotations/shifts" op: BIT src: C bit: 5 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_C, 5); - id: BIT 5, D hex: 0x6A cat: "8-bit rotations/shifts" op: BIT src: D bit: 5 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_D, 5); - id: BIT 5, E hex: 0x6B cat: "8-bit rotations/shifts" op: BIT src: E bit: 5 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_E, 5); - id: BIT 5, H hex: 0x6C cat: "8-bit rotations/shifts" op: BIT src: H bit: 5 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_H, 5); - id: BIT 5, L hex: 0x6D cat: "8-bit rotations/shifts" op: BIT src: L bit: 5 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_L, 5); - id: BIT 5, (HL) hex: 0x6E cat: "8-bit rotations/shifts" op: BIT src: (HL) bit: 5 len: 2 pc: true time: 16 flags: z: Z n: "0" h: "1" c: code: | bit_hl(ctx, 5); - id: BIT 5, A hex: 0x6F cat: "8-bit rotations/shifts" op: BIT src: A bit: 5 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_A, 5); - id: BIT 6, B hex: 0x70 cat: "8-bit rotations/shifts" op: BIT src: B bit: 6 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_B, 6); - id: BIT 6, C hex: 0x71 cat: "8-bit rotations/shifts" op: BIT src: C bit: 6 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_C, 6); - id: BIT 6, D hex: 0x72 cat: "8-bit rotations/shifts" op: BIT src: D bit: 6 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_D, 6); - id: BIT 6, E hex: 0x73 cat: "8-bit rotations/shifts" op: BIT src: E bit: 6 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_E, 6); - id: BIT 6, H hex: 0x74 cat: "8-bit rotations/shifts" op: BIT src: H bit: 6 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_H, 6); - id: BIT 6, L hex: 0x75 cat: "8-bit rotations/shifts" op: BIT src: L bit: 6 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_L, 6); - id: BIT 6, (HL) hex: 0x76 cat: "8-bit rotations/shifts" op: BIT src: (HL) bit: 6 len: 2 pc: true time: 16 flags: z: Z n: "0" h: "1" c: code: | bit_hl(ctx, 6); - id: BIT 6, A hex: 0x77 cat: "8-bit rotations/shifts" op: BIT src: A bit: 6 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_A, 6); - id: BIT 7, B hex: 0x78 cat: "8-bit rotations/shifts" op: BIT src: B bit: 7 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_B, 7); - id: BIT 7, C hex: 0x79 cat: "8-bit rotations/shifts" op: BIT src: C bit: 7 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_C, 7); - id: BIT 7, D hex: 0x7A cat: "8-bit rotations/shifts" op: BIT src: D bit: 7 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_D, 7); - id: BIT 7, E hex: 0x7B cat: "8-bit rotations/shifts" op: BIT src: E bit: 7 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_E, 7); - id: BIT 7, H hex: 0x7C cat: "8-bit rotations/shifts" op: BIT src: H bit: 7 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_H, 7); - id: BIT 7, L hex: 0x7D cat: "8-bit rotations/shifts" op: BIT src: L bit: 7 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_L, 7); - id: BIT 7, (HL) hex: 0x7E cat: "8-bit rotations/shifts" op: BIT src: (HL) bit: 7 len: 2 pc: true time: 16 flags: z: Z n: "0" h: "1" c: code: | bit_hl(ctx, 7); - id: BIT 7, A hex: 0x7F cat: "8-bit rotations/shifts" op: BIT src: A bit: 7 len: 2 pc: true time: 8 flags: z: Z n: "0" h: "1" c: code: | bit_rb(ctx, RB_A, 7); - id: RES 0, B hex: 0x80 cat: "8-bit rotations/shifts" op: RES src: B bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_B, 0); - id: RES 0, C hex: 0x81 cat: "8-bit rotations/shifts" op: RES src: C bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_C, 0); - id: RES 0, D hex: 0x82 cat: "8-bit rotations/shifts" op: RES src: D bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_D, 0); - id: RES 0, E hex: 0x83 cat: "8-bit rotations/shifts" op: RES src: E bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_E, 0); - id: RES 0, H hex: 0x84 cat: "8-bit rotations/shifts" op: RES src: H bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_H, 0); - id: RES 0, L hex: 0x85 cat: "8-bit rotations/shifts" op: RES src: L bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_L, 0); - id: RES 0, (HL) hex: 0x86 cat: "8-bit rotations/shifts" op: RES src: (HL) bit: 0 len: 2 pc: true time: 16 flags: z: n: h: c: code: | res_hl(ctx, 0); - id: RES 0, A hex: 0x87 cat: "8-bit rotations/shifts" op: RES src: A bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_A, 0); - id: RES 1, B hex: 0x88 cat: "8-bit rotations/shifts" op: RES src: B bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_B, 1); - id: RES 1, C hex: 0x89 cat: "8-bit rotations/shifts" op: RES src: C bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_C, 1); - id: RES 1, D hex: 0x8A cat: "8-bit rotations/shifts" op: RES src: D bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_D, 1); - id: RES 1, E hex: 0x8B cat: "8-bit rotations/shifts" op: RES src: E bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_E, 1); - id: RES 1, H hex: 0x8C cat: "8-bit rotations/shifts" op: RES src: H bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_H, 1); - id: RES 1, L hex: 0x8D cat: "8-bit rotations/shifts" op: RES src: L bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_L, 1); - id: RES 1, (HL) hex: 0x8E cat: "8-bit rotations/shifts" op: RES src: (HL) bit: 1 len: 2 pc: true time: 16 flags: z: n: h: c: code: | res_hl(ctx, 1); - id: RES 1, A hex: 0x8F cat: "8-bit rotations/shifts" op: RES src: A bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_A, 1); - id: RES 2, B hex: 0x90 cat: "8-bit rotations/shifts" op: RES src: B bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_B, 2); - id: RES 2, C hex: 0x91 cat: "8-bit rotations/shifts" op: RES src: C bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_C, 2); - id: RES 2, D hex: 0x92 cat: "8-bit rotations/shifts" op: RES src: D bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_D, 2); - id: RES 2, E hex: 0x93 cat: "8-bit rotations/shifts" op: RES src: E bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_E, 2); - id: RES 2, H hex: 0x94 cat: "8-bit rotations/shifts" op: RES src: H bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_H, 2); - id: RES 2, L hex: 0x95 cat: "8-bit rotations/shifts" op: RES src: L bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_L, 2); - id: RES 2, (HL) hex: 0x96 cat: "8-bit rotations/shifts" op: RES src: (HL) bit: 2 len: 2 pc: true time: 16 flags: z: n: h: c: code: | res_hl(ctx, 2); - id: RES 2, A hex: 0x97 cat: "8-bit rotations/shifts" op: RES src: A bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_A, 2); - id: RES 3, B hex: 0x98 cat: "8-bit rotations/shifts" op: RES src: B bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_B, 3); - id: RES 3, C hex: 0x99 cat: "8-bit rotations/shifts" op: RES src: C bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_C, 3); - id: RES 3, D hex: 0x9A cat: "8-bit rotations/shifts" op: RES src: D bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_D, 3); - id: RES 3, E hex: 0x9B cat: "8-bit rotations/shifts" op: RES src: E bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_E, 3); - id: RES 3, H hex: 0x9C cat: "8-bit rotations/shifts" op: RES src: H bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_H, 3); - id: RES 3, L hex: 0x9D cat: "8-bit rotations/shifts" op: RES src: L bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_L, 3); - id: RES 3, (HL) hex: 0x9E cat: "8-bit rotations/shifts" op: RES src: (HL) bit: 3 len: 2 pc: true time: 16 flags: z: n: h: c: code: | res_hl(ctx, 3); - id: RES 3, A hex: 0x9F cat: "8-bit rotations/shifts" op: RES src: A bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_A, 3); - id: RES 4, B hex: 0xA0 cat: "8-bit rotations/shifts" op: RES src: B bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_B, 4); - id: RES 4, C hex: 0xA1 cat: "8-bit rotations/shifts" op: RES src: C bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_C, 4); - id: RES 4, D hex: 0xA2 cat: "8-bit rotations/shifts" op: RES src: D bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_D, 4); - id: RES 4, E hex: 0xA3 cat: "8-bit rotations/shifts" op: RES src: E bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_E, 4); - id: RES 4, H hex: 0xA4 cat: "8-bit rotations/shifts" op: RES src: H bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_H, 4); - id: RES 4, L hex: 0xA5 cat: "8-bit rotations/shifts" op: RES src: L bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_L, 4); - id: RES 4, (HL) hex: 0xA6 cat: "8-bit rotations/shifts" op: RES src: (HL) bit: 4 len: 2 pc: true time: 16 flags: z: n: h: c: code: | res_hl(ctx, 4); - id: RES 4, A hex: 0xA7 cat: "8-bit rotations/shifts" op: RES src: A bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_A, 4); - id: RES 5, B hex: 0xA8 cat: "8-bit rotations/shifts" op: RES src: B bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_B, 5); - id: RES 5, C hex: 0xA9 cat: "8-bit rotations/shifts" op: RES src: C bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_C, 5); - id: RES 5, D hex: 0xAA cat: "8-bit rotations/shifts" op: RES src: D bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_D, 5); - id: RES 5, E hex: 0xAB cat: "8-bit rotations/shifts" op: RES src: E bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_E, 5); - id: RES 5, H hex: 0xAC cat: "8-bit rotations/shifts" op: RES src: H bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_H, 5); - id: RES 5, L hex: 0xAD cat: "8-bit rotations/shifts" op: RES src: L bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_L, 5); - id: RES 5, (HL) hex: 0xAE cat: "8-bit rotations/shifts" op: RES src: (HL) bit: 5 len: 2 pc: true time: 16 flags: z: n: h: c: code: | res_hl(ctx, 5); - id: RES 5, A hex: 0xAF cat: "8-bit rotations/shifts" op: RES src: A bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_A, 5); - id: RES 6, B hex: 0xB0 cat: "8-bit rotations/shifts" op: RES src: B bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_B, 6); - id: RES 6, C hex: 0xB1 cat: "8-bit rotations/shifts" op: RES src: C bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_C, 6); - id: RES 6, D hex: 0xB2 cat: "8-bit rotations/shifts" op: RES src: D bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_D, 6); - id: RES 6, E hex: 0xB3 cat: "8-bit rotations/shifts" op: RES src: E bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_E, 6); - id: RES 6, H hex: 0xB4 cat: "8-bit rotations/shifts" op: RES src: H bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_H, 6); - id: RES 6, L hex: 0xB5 cat: "8-bit rotations/shifts" op: RES src: L bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_L, 6); - id: RES 6, (HL) hex: 0xB6 cat: "8-bit rotations/shifts" op: RES src: (HL) bit: 6 len: 2 pc: true time: 16 flags: z: n: h: c: code: | res_hl(ctx, 6); - id: RES 6, A hex: 0xB7 cat: "8-bit rotations/shifts" op: RES src: A bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_A, 6); - id: RES 7, B hex: 0xB8 cat: "8-bit rotations/shifts" op: RES src: B bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_B, 7); - id: RES 7, C hex: 0xB9 cat: "8-bit rotations/shifts" op: RES src: C bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_C, 7); - id: RES 7, D hex: 0xBA cat: "8-bit rotations/shifts" op: RES src: D bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_D, 7); - id: RES 7, E hex: 0xBB cat: "8-bit rotations/shifts" op: RES src: E bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_E, 7); - id: RES 7, H hex: 0xBC cat: "8-bit rotations/shifts" op: RES src: H bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_H, 7); - id: RES 7, L hex: 0xBD cat: "8-bit rotations/shifts" op: RES src: L bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_L, 7); - id: RES 7, (HL) hex: 0xBE cat: "8-bit rotations/shifts" op: RES src: (HL) bit: 7 len: 2 pc: true time: 16 flags: z: n: h: c: code: | res_hl(ctx, 7); - id: RES 7, A hex: 0xBF cat: "8-bit rotations/shifts" op: RES src: A bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | res_rb(ctx, RB_A, 7); - id: SET 0, B hex: 0xC0 cat: "8-bit rotations/shifts" op: SET src: B bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_B, 0); - id: SET 0, C hex: 0xC1 cat: "8-bit rotations/shifts" op: SET src: C bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_C, 0); - id: SET 0, D hex: 0xC2 cat: "8-bit rotations/shifts" op: SET src: D bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_D, 0); - id: SET 0, E hex: 0xC3 cat: "8-bit rotations/shifts" op: SET src: E bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_E, 0); - id: SET 0, H hex: 0xC4 cat: "8-bit rotations/shifts" op: SET src: H bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_H, 0); - id: SET 0, L hex: 0xC5 cat: "8-bit rotations/shifts" op: SET src: L bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_L, 0); - id: SET 0, (HL) hex: 0xC6 cat: "8-bit rotations/shifts" op: SET src: (HL) bit: 0 len: 2 pc: true time: 16 flags: z: n: h: c: code: | set_hl(ctx, 0); - id: SET 0, A hex: 0xC7 cat: "8-bit rotations/shifts" op: SET src: A bit: 0 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_A, 0); - id: SET 1, B hex: 0xC8 cat: "8-bit rotations/shifts" op: SET src: B bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_B, 1); - id: SET 1, C hex: 0xC9 cat: "8-bit rotations/shifts" op: SET src: C bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_C, 1); - id: SET 1, D hex: 0xCA cat: "8-bit rotations/shifts" op: SET src: D bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_D, 1); - id: SET 1, E hex: 0xCB cat: "8-bit rotations/shifts" op: SET src: E bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_E, 1); - id: SET 1, H hex: 0xCC cat: "8-bit rotations/shifts" op: SET src: H bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_H, 1); - id: SET 1, L hex: 0xCD cat: "8-bit rotations/shifts" op: SET src: L bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_L, 1); - id: SET 1, (HL) hex: 0xCE cat: "8-bit rotations/shifts" op: SET src: (HL) bit: 1 len: 2 pc: true time: 16 flags: z: n: h: c: code: | set_hl(ctx, 1); - id: SET 1, A hex: 0xCF cat: "8-bit rotations/shifts" op: SET src: A bit: 1 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_A, 1); - id: SET 2, B hex: 0xD0 cat: "8-bit rotations/shifts" op: SET src: B bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_B, 2); - id: SET 2, C hex: 0xD1 cat: "8-bit rotations/shifts" op: SET src: C bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_C, 2); - id: SET 2, D hex: 0xD2 cat: "8-bit rotations/shifts" op: SET src: D bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_D, 2); - id: SET 2, E hex: 0xD3 cat: "8-bit rotations/shifts" op: SET src: E bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_E, 2); - id: SET 2, H hex: 0xD4 cat: "8-bit rotations/shifts" op: SET src: H bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_H, 2); - id: SET 2, L hex: 0xD5 cat: "8-bit rotations/shifts" op: SET src: L bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_L, 2); - id: SET 2, (HL) hex: 0xD6 cat: "8-bit rotations/shifts" op: SET src: (HL) bit: 2 len: 2 pc: true time: 16 flags: z: n: h: c: code: | set_hl(ctx, 2); - id: SET 2, A hex: 0xD7 cat: "8-bit rotations/shifts" op: SET src: A bit: 2 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_A, 2); - id: SET 3, B hex: 0xD8 cat: "8-bit rotations/shifts" op: SET src: B bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_B, 3); - id: SET 3, C hex: 0xD9 cat: "8-bit rotations/shifts" op: SET src: C bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_C, 3); - id: SET 3, D hex: 0xDA cat: "8-bit rotations/shifts" op: SET src: D bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_D, 3); - id: SET 3, E hex: 0xDB cat: "8-bit rotations/shifts" op: SET src: E bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_E, 3); - id: SET 3, H hex: 0xDC cat: "8-bit rotations/shifts" op: SET src: H bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_H, 3); - id: SET 3, L hex: 0xDD cat: "8-bit rotations/shifts" op: SET src: L bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_L, 3); - id: SET 3, (HL) hex: 0xDE cat: "8-bit rotations/shifts" op: SET src: (HL) bit: 3 len: 2 pc: true time: 16 flags: z: n: h: c: code: | set_hl(ctx, 3); - id: SET 3, A hex: 0xDF cat: "8-bit rotations/shifts" op: SET src: A bit: 3 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_A, 3); - id: SET 4, B hex: 0xE0 cat: "8-bit rotations/shifts" op: SET src: B bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_B, 4); - id: SET 4, C hex: 0xE1 cat: "8-bit rotations/shifts" op: SET src: C bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_C, 4); - id: SET 4, D hex: 0xE2 cat: "8-bit rotations/shifts" op: SET src: D bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_D, 4); - id: SET 4, E hex: 0xE3 cat: "8-bit rotations/shifts" op: SET src: E bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_E, 4); - id: SET 4, H hex: 0xE4 cat: "8-bit rotations/shifts" op: SET src: H bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_H, 4); - id: SET 4, L hex: 0xE5 cat: "8-bit rotations/shifts" op: SET src: L bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_L, 4); - id: SET 4, (HL) hex: 0xE6 cat: "8-bit rotations/shifts" op: SET src: (HL) bit: 4 len: 2 pc: true time: 16 flags: z: n: h: c: code: | set_hl(ctx, 4); - id: SET 4, A hex: 0xE7 cat: "8-bit rotations/shifts" op: SET src: A bit: 4 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_A, 4); - id: SET 5, B hex: 0xE8 cat: "8-bit rotations/shifts" op: SET src: B bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_B, 5); - id: SET 5, C hex: 0xE9 cat: "8-bit rotations/shifts" op: SET src: C bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_C, 5); - id: SET 5, D hex: 0xEA cat: "8-bit rotations/shifts" op: SET src: D bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_D, 5); - id: SET 5, E hex: 0xEB cat: "8-bit rotations/shifts" op: SET src: E bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_E, 5); - id: SET 5, H hex: 0xEC cat: "8-bit rotations/shifts" op: SET src: H bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_H, 5); - id: SET 5, L hex: 0xED cat: "8-bit rotations/shifts" op: SET src: L bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_L, 5); - id: SET 5, (HL) hex: 0xEE cat: "8-bit rotations/shifts" op: SET src: (HL) bit: 5 len: 2 pc: true time: 16 flags: z: n: h: c: code: | set_hl(ctx, 5); - id: SET 5, A hex: 0xEF cat: "8-bit rotations/shifts" op: SET src: A bit: 5 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_A, 5); - id: SET 6, B hex: 0xF0 cat: "8-bit rotations/shifts" op: SET src: B bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_B, 6); - id: SET 6, C hex: 0xF1 cat: "8-bit rotations/shifts" op: SET src: C bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_C, 6); - id: SET 6, D hex: 0xF2 cat: "8-bit rotations/shifts" op: SET src: D bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_D, 6); - id: SET 6, E hex: 0xF3 cat: "8-bit rotations/shifts" op: SET src: E bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_E, 6); - id: SET 6, H hex: 0xF4 cat: "8-bit rotations/shifts" op: SET src: H bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_H, 6); - id: SET 6, L hex: 0xF5 cat: "8-bit rotations/shifts" op: SET src: L bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_L, 6); - id: SET 6, (HL) hex: 0xF6 cat: "8-bit rotations/shifts" op: SET src: (HL) bit: 6 len: 2 pc: true time: 16 flags: z: n: h: c: code: | set_hl(ctx, 6); - id: SET 6, A hex: 0xF7 cat: "8-bit rotations/shifts" op: SET src: A bit: 6 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_A, 6); - id: SET 7, B hex: 0xF8 cat: "8-bit rotations/shifts" op: SET src: B bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_B, 7); - id: SET 7, C hex: 0xF9 cat: "8-bit rotations/shifts" op: SET src: C bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_C, 7); - id: SET 7, D hex: 0xFA cat: "8-bit rotations/shifts" op: SET src: D bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_D, 7); - id: SET 7, E hex: 0xFB cat: "8-bit rotations/shifts" op: SET src: E bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_E, 7); - id: SET 7, H hex: 0xFC cat: "8-bit rotations/shifts" op: SET src: H bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_H, 7); - id: SET 7, L hex: 0xFD cat: "8-bit rotations/shifts" op: SET src: L bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_H, 7); - id: SET 7, (HL) hex: 0xFE cat: "8-bit rotations/shifts" op: SET src: (HL) bit: 7 len: 2 pc: true time: 16 flags: z: n: h: c: code: | set_hl(ctx, 7); - id: SET 7, A hex: 0xFF cat: "8-bit rotations/shifts" op: SET src: A bit: 7 len: 2 pc: true time: 8 flags: z: n: h: c: code: | set_rb(ctx, RB_A, 7); templates: main: | #include // memset() #include // uint8_t ,etc #include // bool #include // snprintf() #include "gb.h" #define UNUSED(a) ((void) (a)) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define BETWEEN(v, a, b) (((v) >= (a)) && ((v) <= (b))) // cpu flags #define FLAG(ctx, f) (cpu_rb(ctx, RB_F) & (F_##f)) #define F_Z (1 << 7) #define F_N (1 << 6) #define F_H (1 << 5) #define F_C (1 << 4) // interrupts #define IRQ_VBLANK (1) #define IRQ_LCDC (1 << 1) #define IRQ_TIMER (1 << 2) #define IRQ_SERIAL (1 << 3) #define IRQ_P1 (1 << 4) typedef enum { RB_A, RB_F, RB_B, RB_C, RB_D, RB_E, RB_H, RB_L, RB_LAST } rb_t; typedef enum { RW_AF, RW_BC, RW_DE, RW_HL, RW_SP, RW_PC, RW_LAST, } rw_t; // gb-manual, p23 #define P1_MODE_NONE 0 #define P1_MODE_P14 1 #define P1_MODE_P15 2 #define GPU_MODE_OAM 2 #define GPU_MODE_VRAM 3 #define GPU_MODE_HBLANK 0 #define GPU_MODE_VBLANK 1 #define CART_TYPE_ROM_ONLY 0x00 #define CART_TYPE_MBC1 0x01 #define CART_TYPE_MBC1_RAM 0x02 #define CART_TYPE_MBC1_RAM_BATTERY 0x03 #define CART_TYPE_MBC2 0x05 #define CART_TYPE_MBC2_BATTERY 0x06 #define CART_TYPE_ROM_RAM 0x08 #define CART_TYPE_ROM_RAM_BATTERY 0x09 #define CART_TYPE_MMM01 0x0B #define CART_TYPE_MMM01_RAM 0x0C #define CART_TYPE_MMM01_RAM_BATTERY 0x0D #define CART_TYPE_MBC3_TIMER_BATTERY 0x0F #define CART_TYPE_MBC3_TIMER_RAM_BATTERY 0x10 #define CART_TYPE_MBC3 0x11 #define CART_TYPE_MBC3_RAM 0x12 #define CART_TYPE_MBC3_RAM_BATTERY 0x13 #define CART_TYPE_MBC5 0x19 #define CART_TYPE_MBC5_RAM 0x1A #define CART_TYPE_MBC5_RAM_BATTERY 0x1B #define CART_TYPE_MBC5_RUMBLE 0x1C #define CART_TYPE_MBC5_RUMBLE_RAM 0x1D #define CART_TYPE_MBC5_RUMBLE_RAM_BATTERY 0x1E #define CART_TYPE_MBC6 0x20 #define CART_TYPE_MBC7_SENSOR_RUMBLE_RAM_BATTERY 0x22 #define CART_TYPE_POCKET_CAMERA 0xFC #define CART_TYPE_BANDAI_TAMA5 0xFD #define CART_TYPE_HuC3 0xFE #define CART_TYPE_HuC1_RAM_BATTERY 0xFF static uint8_t rom_get_cart_type( const gb_t * const ctx ) { return ctx->mmu.rom[0x147]; } #define MBC_TYPE_NONE 0 #define MBC_TYPE_MBC1 1 #define MBC_TYPE_MBC2 2 #define MBC_TYPE_ROM_RAM 3 #define MBC_TYPE_MMM01 4 #define MBC_TYPE_MBC3 5 #define MBC_TYPE_MBC5 6 #define MBC_TYPE_MBC6 7 #define MBC_TYPE_MBC7 8 #define MBC_TYPE_UNKNOWN 9 static uint8_t rom_get_mbc_type( const gb_t * const ctx ) { switch (rom_get_cart_type(ctx)) { case CART_TYPE_ROM_ONLY: return MBC_TYPE_NONE; case CART_TYPE_MBC1: case CART_TYPE_MBC1_RAM: case CART_TYPE_MBC1_RAM_BATTERY: return MBC_TYPE_MBC1; case CART_TYPE_MBC2: case CART_TYPE_MBC2_BATTERY: return MBC_TYPE_MBC2; case CART_TYPE_ROM_RAM: case CART_TYPE_ROM_RAM_BATTERY: return MBC_TYPE_ROM_RAM; case CART_TYPE_MMM01: case CART_TYPE_MMM01_RAM: case CART_TYPE_MMM01_RAM_BATTERY: return MBC_TYPE_MMM01; case CART_TYPE_MBC3_TIMER_BATTERY: case CART_TYPE_MBC3_TIMER_RAM_BATTERY: case CART_TYPE_MBC3: case CART_TYPE_MBC3_RAM: case CART_TYPE_MBC3_RAM_BATTERY: return MBC_TYPE_MBC3; case CART_TYPE_MBC5: case CART_TYPE_MBC5_RAM: case CART_TYPE_MBC5_RAM_BATTERY: case CART_TYPE_MBC5_RUMBLE: case CART_TYPE_MBC5_RUMBLE_RAM: case CART_TYPE_MBC5_RUMBLE_RAM_BATTERY: return MBC_TYPE_MBC5; case CART_TYPE_MBC6: return MBC_TYPE_MBC6; case CART_TYPE_MBC7_SENSOR_RUMBLE_RAM_BATTERY: return MBC_TYPE_MBC7; case CART_TYPE_POCKET_CAMERA: case CART_TYPE_BANDAI_TAMA5: case CART_TYPE_HuC3: case CART_TYPE_HuC1_RAM_BATTERY: // TODO default: return MBC_TYPE_UNKNOWN; } } /******************/ /* mbc1 functions */ /******************/ static uint32_t mbc1_rom_get_addr( gb_t * const ctx, const uint16_t addr ) { // mbc1 rom1 banking (TCAGBD.pdf, 11.2.2) // A ABBB BBCC CCCC CCCC CCCC return ( // A: ram_bank (2 bits, if rom_ram_mode == 0) (((ctx->mmu.mbc1.rom_ram_mode ? 0 : ctx->mmu.mbc1.ram_bank) & 0x3) << 19) | // B: rom_bank (5 bits, low bit set) (((ctx->mmu.mbc1.rom_bank & 0x1F) | 0x1) << 14) | // C: address (14 bits) ((addr - 0x4000) & 0x3FFF) ); } static uint8_t mbc1_rom_rb( gb_t * const ctx, const uint16_t addr ) { switch (addr & 0xF000) { case 0x0000: case 0x1000: case 0x2000: case 0x3000: #if 0 // bios memory (maybe) if (ctx->mmu.in_bios) { if (addr < 0x100) { return ctx->mmu.bios[addr]; } else { ctx->mmu.in_bios = false; } } #endif /* 0 */ // ROM0 (16k, always mapped) return ctx->mmu.rom[addr]; case 0x4000: case 0x5000: case 0x6000: case 0x7000: // ROM1 (16k, banked) { // mbc1 rom1 banking (TCAGBD.pdf, 11.2.2) const uint32_t addr_ofs = mbc1_rom_get_addr(ctx, addr); return addr_ofs < ctx->mmu.rom_size ? ctx->mmu.rom[addr_ofs] : 0; } default: // never reached return 0; } } static void mbc1_rom_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { switch (addr & 0xF000) { case 0x0000: case 0x1000: // toggle ram_enable ctx->mmu.mbc1.ram_enable = ((val & 0x0F) == 0x0A); break; case 0x2000: case 0x3000: ctx->mmu.mbc1.rom_bank = val & 0x1F; if (ctx->config && ctx->config->on_set_rom_bank) { // notify callback ctx->config->on_set_rom_bank(ctx, val & 0x1F); } break; case 0x4000: case 0x5000: // set ram_bank/upper_rom_bank bits ctx->mmu.mbc1.ram_bank = val & 0x03; if (ctx->config && ctx->config->on_set_ram_bank) { // notify callback ctx->config->on_set_ram_bank(ctx, val & 0x03); } break; case 0x6000: case 0x7000: // set rom/ram mode ctx->mmu.mbc1.rom_ram_mode = val & 0x1; break; default: // never reached break; } } static uint16_t mbc1_eram_get_addr( const gb_t * const ctx, const uint16_t addr ) { // switchable ram bank // AAB BBBB BBBB BBBB return ( // A: ram_bank (2 bits, if rom_ram_mode == 1) (((ctx->mmu.mbc1.rom_ram_mode ? ctx->mmu.mbc1.ram_bank : 0) & 0x3) << 13) | // B: address (13 bits) (addr & 0x1FFF) ); } static uint8_t mbc1_eram_rb( const gb_t * const ctx, const uint16_t addr ) { if (ctx->mmu.eram && ctx->mmu.mbc1.ram_enable) { return ctx->mmu.eram[mbc1_eram_get_addr(ctx, addr)]; } else { // FIXME: what do we do with no eram? return 0; } } static void mbc1_eram_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { if (ctx->mmu.eram && ctx->mmu.mbc1.ram_enable) { ctx->mmu.eram[mbc1_eram_get_addr(ctx, addr)] = val; } } /******************/ /* mbc2 functions */ /******************/ static uint32_t mbc2_rom_get_addr( gb_t * const ctx, const uint16_t addr ) { // mbc2 rom1 banking (TCAGBD.pdf, 11.2.3) // AA AABB BBBB BBBB BBBB return ( // B: rom_bank (4 bits, low bit set) ((ctx->mmu.mbc2.rom_bank & 0xF) << 13) | // C: address (14 bits) ((addr - 0x4000) & 0x3FFF) ); } static uint8_t mbc2_rom_rb( gb_t * const ctx, const uint16_t addr ) { switch (addr & 0xF000) { case 0x0000: case 0x1000: case 0x2000: case 0x3000: #if 0 // bios memory (maybe) if (ctx->mmu.in_bios) { if (addr < 0x100) { return ctx->mmu.bios[addr]; } else { ctx->mmu.in_bios = false; } } #endif /* 0 */ // ROM0 (16k, always mapped) return ctx->mmu.rom[addr]; case 0x4000: case 0x5000: case 0x6000: case 0x7000: // ROM1 (16k, banked) { const uint32_t addr_ofs = mbc2_rom_get_addr(ctx, addr); return addr_ofs < ctx->mmu.rom_size ? ctx->mmu.rom[addr_ofs] : 0; } default: // never reached return 0; } } static void mbc2_rom_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { switch (addr & 0xF000) { case 0x0000: case 0x1000: if (!(addr & 0x10)) { // toggle ram_enable ctx->mmu.mbc2.ram_enable = ((val & 0x0F) == 0x0A); } break; case 0x2000: case 0x3000: if (addr & 0x10) { // set rom bank ctx->mmu.mbc2.rom_bank = val & 0x0F; } break; default: // do nothing break; } } static uint16_t mbc2_eram_get_addr( const gb_t * const ctx, const uint16_t addr ) { UNUSED(ctx); return (addr & 0x1FF); } static uint8_t mbc2_eram_rb( const gb_t * const ctx, const uint16_t addr ) { if (ctx->mmu.eram && ctx->mmu.mbc2.ram_enable) { return ctx->mmu.eram[mbc2_eram_get_addr(ctx, addr)] & 0x0F; } else { return 0; } } static void mbc2_eram_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { if (ctx->mmu.eram && ctx->mmu.mbc2.ram_enable) { ctx->mmu.eram[mbc2_eram_get_addr(ctx, addr)] = val & 0x0F; } } /************************/ /* timer shift function */ /************************/ static uint8_t timer_get_shift( const gb_t * const ctx ) { switch (ctx->timer.tac & 0x3) { case 0: return 10; /* CPU clock / 1024, 4096Hz */ case 1: return 4; /* CPU clock / 16, 262144Hz */ case 2: return 6; /* CPU clock / 64, 65536Hz */ case 3: return 8; /* CPU clock / 256, 16384Hz */ default: // never reached return 0; } } /***************/ /* mmu OAM dma */ /***************/ // forward references for mmu_oam_dma() static uint8_t mmu_rb(gb_t * const, const uint16_t); static void mmu_wb(gb_t * const, const uint16_t, const uint8_t); static void mmu_oam_dma( gb_t * const ctx, const uint8_t val ) { const uint16_t src_addr = (val << 8); // copy 160 bytes of data to OAM // (src: http://gbdev.gg8.se/wiki/articles/Video_Display#LCD_OAM_DMA_Transfers) for (uint8_t i = 0; i < 160; i++) { mmu_wb(ctx, 0xFE00 + i, mmu_rb(ctx, src_addr + i)); } } /**********************/ /* mmu port functions */ /**********************/ #define PORT_P1 0xFF00 // timer registers #define PORT_DIV 0xFF04 #define PORT_TIMA 0xFF05 #define PORT_TMA 0xFF06 #define PORT_TAC 0xFF07 // interrupt registers #define PORT_IE 0xFFFF #define PORT_IF 0xFF0F // lcd ports #define PORT_LCDC 0xFF40 #define PORT_STAT 0xFF41 #define PORT_SCY 0xFF42 #define PORT_SCX 0xFF43 #define PORT_LY 0xFF44 #define PORT_LYC 0xFF45 #define PORT_DMA 0xFF46 #define PORT_BGP 0xFF47 #define PORT_OBP0 0xFF48 #define PORT_OBP1 0xFF49 #define PORT_WY 0xFF4A #define PORT_WX 0xFF4B // forward references for mmu_rp()/mmu_wp() static void gpu_set_line(gb_t * const ctx, const uint8_t line); static void gpu_set_mode(gb_t * const ctx, const uint8_t mode); static bool gpu_is_active(const gb_t * const ctx); static uint8_t gpu_get_mode(const gb_t * const ctx); static uint8_t mmu_rp( const gb_t * const ctx, const uint16_t addr ) { switch (addr) { case PORT_IE: // interrupt enabled mask return ctx->mmu.ie & 0x1F; break; case PORT_IF: // interrupt flags return ctx->mmu.iv & 0x1F; break; case PORT_P1: // buttons (p1) switch (ctx->mmu.p1_mode) { case P1_MODE_P14: return ctx->mmu.btns & 0xF; case P1_MODE_P15: return (ctx->mmu.btns & 0xF0) >> 4; default: return 0; } break; case PORT_DIV: return (ctx->timer.div & 0xFF00) >> 8; break; case PORT_TIMA: return (ctx->timer.tima >> timer_get_shift(ctx)) & 0xFF; break; case PORT_TMA: return ctx->timer.tma; break; case PORT_TAC: return ctx->timer.tac & 0x7; break; case PORT_LCDC: return ctx->gpu.lcdc; break; case PORT_STAT: return (ctx->gpu.stat & 0xF8) | ((ctx->gpu.line == ctx->gpu.lyc) ? (1 << 3) : 0) | // always return mode 1 if lcd is disabled (gpu_is_active(ctx) ? (ctx->gpu.mode & 0x3) : 1); break; case PORT_SCY: return ctx->gpu.scy; break; case PORT_SCX: return ctx->gpu.scx; break; case PORT_LY: // FIXME: is this correct? return gpu_is_active(ctx) ? ctx->gpu.line : 144; break; case PORT_LYC: return ctx->gpu.lyc; break; case PORT_DMA: // write-only (gb-manual, p62) return 0; break; case PORT_BGP: return ctx->gpu.bgp; break; case PORT_OBP0: return ctx->gpu.obp0; break; case PORT_OBP1: return ctx->gpu.obp1; break; case PORT_WY: return ctx->gpu.wy; break; case PORT_WX: return ctx->gpu.wx; break; default: // TODO: io ports return 0; } } static void mmu_wp( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { switch (addr) { case PORT_IE: // interrupt enabled mask ctx->mmu.ie = (val & 0x1F); break; case PORT_IF: // interrupt flags ctx->mmu.iv = (val & 0x1F); break; case PORT_P1: // buttons (p1) switch (val) { case 0x10: ctx->mmu.p1_mode = P1_MODE_P14; break; case 0x20: ctx->mmu.p1_mode = P1_MODE_P15; break; default: // TODO: io ports break; } break; case PORT_DIV: // reset to zero regardless of value ctx->timer.div = 0; break; case PORT_TIMA: // FIXME: is this right? ctx->timer.tima = val; break; case PORT_TMA: ctx->timer.tima = val; break; case PORT_TAC: ctx->timer.tima = val & 0x7; break; case PORT_LCDC: ctx->gpu.lcdc = val; if (gpu_is_active(ctx)) { // reset line, mode, and clock gpu_set_line(ctx, 0); gpu_set_mode(ctx, GPU_MODE_OAM); ctx->gpu.clock = 0; } break; case PORT_STAT: ctx->gpu.stat = (val & 0xF8); break; case PORT_SCY: ctx->gpu.scy = val; break; case PORT_SCX: ctx->gpu.scx = val; break; case PORT_LY: // NOTE: according to URL below writing to this register zeroes it: // (src: http://gbdev.gg8.se/wiki/articles/Video_Display) gpu_set_line(ctx, 0); break; case PORT_LYC: ctx->gpu.lyc = val; break; case PORT_DMA: mmu_oam_dma(ctx, val); break; case PORT_BGP: ctx->gpu.bgp = val; break; case PORT_OBP0: ctx->gpu.obp0 = val; break; case PORT_OBP1: ctx->gpu.obp1 = val; break; case PORT_WY: ctx->gpu.wy = val; break; case PORT_WX: ctx->gpu.wx = val; break; default: // TODO: io ports break; } } /*****************/ /* mmu functions */ /*****************/ static uint8_t rom_rb( gb_t * const ctx, const uint16_t addr ) { switch (rom_get_mbc_type(ctx)) { case MBC_TYPE_NONE: return ctx->mmu.rom[addr]; case MBC_TYPE_MBC1: return mbc1_rom_rb(ctx, addr); case MBC_TYPE_MBC2: return mbc2_rom_rb(ctx, addr); default: // TODO: implement remaining MBC types return 0; } } static uint8_t eram_rb( const gb_t * const ctx, const uint16_t addr ) { // switchable external ram bank (8k, banked, optional) switch (rom_get_mbc_type(ctx)) { case MBC_TYPE_MBC1: return mbc1_eram_rb(ctx, addr); case MBC_TYPE_MBC2: return mbc2_eram_rb(ctx, addr); case MBC_TYPE_NONE: default: return 0; } } #if 0 static uint8_t old_vram_rb( const gb_t * const ctx, const uint16_t addr ) { switch (gpu_get_mode(ctx)) { case GPU_MODE_VRAM: return 0xFF; default: // return vram (8k) return ctx->mmu.vram[addr & 0x1FFF]; } } static uint8_t old_oam_rb( const gb_t * const ctx, const uint16_t addr ) { // NOTE: gpu_get_mode() returns VBLANK if gpu is inactive switch (gpu_get_mode(ctx)) { case GPU_MODE_HBLANK: case GPU_MODE_VBLANK: // oam memory (160 bytes): return ctx->mmu.oam[addr - 0xFE00]; default: return 0; } } #endif /* 0 */ static uint8_t vram_rb( const gb_t * const ctx, const uint16_t addr ) { // return vram (8k) return ctx->mmu.vram[addr & 0x1FFF]; } static uint8_t oam_rb( const gb_t * const ctx, const uint16_t addr ) { // oam memory (160 bytes): return ctx->mmu.oam[addr - 0xFE00]; } static uint8_t ram_rb( gb_t * const ctx, const uint16_t addr ) { switch (addr & 0xF000) { case 0x8000: case 0x9000: // return vram (8k) return vram_rb(ctx, addr); case 0xA000: case 0xB000: // switchable external ram bank (8k, banked, optional) return eram_rb(ctx, addr); case 0xC000: // working ram (8k) case 0xD000: case 0xE000: // working ram (shadow) return ctx->mmu.ram[addr & 0x1FFF]; case 0xF000: switch (addr & 0x0F00) { case 0x0E00: if (addr < 0xFEA0) { return oam_rb(ctx, addr); } else { // rest of page reads as zero return 0; } case 0x0F00: if (addr == PORT_IE || addr < 0xFF80) { // io port return mmu_rp(ctx, addr); } else { // zero page return ctx->mmu.zram[addr & 0x7F]; } default: // working ram (<0xFE00, 8k, shadow) return ctx->mmu.ram[addr & 0x1FFF]; } default: // never reached return 0; } } static uint8_t mmu_rb( gb_t * const ctx, const uint16_t addr ) { const uint8_t val = (addr & 0x8000) ? ram_rb(ctx, addr) : rom_rb(ctx, addr); if (ctx->config && ctx->config->on_mmu_rb) { ctx->config->on_mmu_rb(ctx, addr, val); } return val; } static void rom_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { switch (rom_get_mbc_type(ctx)) { case MBC_TYPE_MBC1: mbc1_rom_wb(ctx, addr, val); break; case MBC_TYPE_MBC2: mbc2_rom_wb(ctx, addr, val); break; default: // do nothing break; } } static void eram_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { switch (rom_get_mbc_type(ctx)) { case MBC_TYPE_MBC1: mbc1_eram_wb(ctx, addr, val); break; case MBC_TYPE_MBC2: mbc2_eram_wb(ctx, addr, val); break; case MBC_TYPE_NONE: // TODO: implement remaining mbcs if (ctx->mmu.eram) { // external ram (8k, optional) ctx->mmu.eram[addr & 0x1FFF] = val; } break; default: // do nothing break; } } #if 0 static void old_vram_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { // // NOTE: gpu_get_mode() returns VBLANK if lcd is inactive switch (gpu_get_mode(ctx)) { case GPU_MODE_VRAM: // do nothing break; default: // write to vram (8k) ctx->mmu.vram[addr & 0x1FFF] = val; break; } } static void old_oam_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { // NOTE: gpu_get_mode() returns VBLANK if lcd is inactive switch (gpu_get_mode(ctx) & 0x3) { case GPU_MODE_HBLANK: case GPU_MODE_VBLANK: // oam memory (160 bytes): ctx->mmu.oam[addr - 0xFE00] = val; // invalidate oam cache ctx->gpu.oam_dirty = true; break; default: // do nothing break; } } #endif /* 0 */ static void vram_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { // write to vram (8k) ctx->mmu.vram[addr & 0x1FFF] = val; } static void oam_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { // oam memory (160 bytes): ctx->mmu.oam[addr - 0xFE00] = val; if (ctx->config && ctx->config->on_oam_wb) { ctx->config->on_oam_wb(ctx, addr, val); } // invalidate oam cache ctx->gpu.oam_dirty = true; } static void ram_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { switch (addr & 0xF000) { case 0x8000: case 0x9000: vram_wb(ctx, addr, val); break; case 0xA000: case 0xB000: eram_wb(ctx, addr, val); break; case 0xC000: // working ram (8k) case 0xD000: case 0xE000: // working ram (8k, shadow) ctx->mmu.ram[addr & 0x1FFF] = val; break; case 0xF000: switch (addr & 0x0F00) { case 0x0E00: if (addr < 0xFEA0) { // oam memory (160 bytes): oam_wb(ctx, addr, val); } break; case 0x0F00: if (addr == PORT_IE || addr < 0xFF80) { // io ports mmu_wp(ctx, addr, val); } else { // zero page ctx->mmu.zram[addr & 0x7F] = val; } break; default: // working ram (<0xFE00, 8k, shadow) ctx->mmu.ram[addr & 0x1FFF] = val; break; } break; default: // never reached break; } } static void mmu_wb( gb_t * const ctx, const uint16_t addr, const uint8_t val ) { if (ctx->config && ctx->config->on_mmu_wb) { ctx->config->on_mmu_wb(ctx, addr, val); } if (addr & 0xF000) { ram_wb(ctx, addr, val); } else { rom_wb(ctx, addr, val); } } static uint16_t mmu_rw( gb_t * const ctx, const uint16_t addr ) { // FIXME return (((uint16_t) mmu_rb(ctx, addr + 1)) << 8) + mmu_rb(ctx, addr); } static void mmu_ww( gb_t * const ctx, const uint16_t addr, const uint16_t val ) { // write lsb, msb (little endian) mmu_wb(ctx, addr, val & 0xFF); mmu_wb(ctx, addr + 1, val >> 8); } static uint16_t cpu_rw( const gb_t * const ctx, const rw_t reg ) { return ctx->cpu.rs[reg]; } static void cpu_ww( gb_t * const ctx, const rw_t reg, const uint16_t val ) { ctx->cpu.rs[reg] = val; } static uint8_t cpu_rb( const gb_t * const ctx, const rb_t reg ) { switch (reg) { case RB_A: return cpu_rw(ctx, RW_AF) >> 8; case RB_F: // FIXME: should be 0xF0 to mask flags return cpu_rw(ctx, RW_AF) & 0xFF; case RB_B: return cpu_rw(ctx, RW_BC) >> 8; case RB_C: return cpu_rw(ctx, RW_BC) & 0xFF; case RB_D: return cpu_rw(ctx, RW_DE) >> 8; case RB_E: return cpu_rw(ctx, RW_DE) & 0xFF; case RB_H: return cpu_rw(ctx, RW_HL) >> 8; case RB_L: return cpu_rw(ctx, RW_HL) & 0xFF; default: return 0; } } static void cpu_wb( gb_t * const ctx, const rb_t reg, const uint8_t val ) { switch (reg) { case RB_A: // FIXME: second mask should be 0xF0 to mask flags ctx->cpu.rs[RW_AF] = (((uint16_t) val) << 8) | (ctx->cpu.rs[RW_AF] & 0xFF); break; case RB_F: ctx->cpu.rs[RW_AF] = (ctx->cpu.rs[RW_AF] & 0xFF00) | val; break; case RB_B: ctx->cpu.rs[RW_BC] = (((uint16_t) val) << 8) | (ctx->cpu.rs[RW_BC] & 0xFF); break; case RB_C: ctx->cpu.rs[RW_BC] = (ctx->cpu.rs[RW_BC] & 0xFF00) | val; break; case RB_D: ctx->cpu.rs[RW_DE] = (((uint16_t) val) << 8) | (ctx->cpu.rs[RW_DE] & 0xFF); break; case RB_E: ctx->cpu.rs[RW_DE] = (ctx->cpu.rs[RW_DE] & 0xFF00) | val; break; case RB_H: ctx->cpu.rs[RW_HL] = (((uint16_t) val) << 8) | (ctx->cpu.rs[RW_HL] & 0xFF); break; case RB_L: ctx->cpu.rs[RW_HL] = (ctx->cpu.rs[RW_HL] & 0xFF00) | val; break; default: // FIXME: do what now? return; } } static void cpu_wf( gb_t * const ctx, const uint8_t mask, const uint8_t flags ) { const uint8_t of = cpu_rb(ctx, RB_F); cpu_wb(ctx, RB_F, ( (((mask & F_Z) ? flags : of) & F_Z) | (((mask & F_N) ? flags : of) & F_N) | (((mask & F_H) ? flags : of) & F_H) | (((mask & F_C) ? flags : of) & F_C) )); } static void cpu_irq( gb_t * const ctx, const uint8_t mask ) { // trigger interrupt mask mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) | mask); } static void cpu_set_state( gb_t * const ctx, const uint16_t pc, const gb_cpu_state_t state ) { ctx->cpu.state = state; UNUSED(pc); if (ctx->config && ctx->config->on_set_cpu_state) { ctx->config->on_set_cpu_state(ctx, state); } } static uint8_t inc( gb_t * const ctx, const uint8_t o ) { const uint8_t n = o + 1; // set flags cpu_wf(ctx, F_Z | F_N | F_H, ( (n ? 0 : F_Z) | (((o & 0x0F) == 0x0F) ? F_H : 0) )); // return new value return n; } static void inc_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, inc(ctx, cpu_rb(ctx, reg))); } static void inc_hl_ptr( gb_t * const ctx ) { const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, inc(ctx, mmu_rb(ctx, addr))); } static uint8_t dec( gb_t * const ctx, const uint8_t o ) { // cal new value const uint8_t n = o - 1; // set flags cpu_wf(ctx, F_Z | F_N | F_H, ( (n ? 0 : F_Z) | F_N | (((o ^ n) & 0x10) ? F_H : 0) )); // return new value return n; } static void dec_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, dec(ctx, cpu_rb(ctx, reg))); } static void dec_hl_ptr( gb_t * const ctx ) { // write flags const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, dec(ctx, mmu_rb(ctx, addr))); } static void add_rw_rw( gb_t * const ctx, const rw_t dst_reg, const rw_t src_reg ) { // get old values and sum const uint16_t dst_val = cpu_rw(ctx, dst_reg), src_val = cpu_rw(ctx, src_reg); const uint32_t n = ((uint32_t) dst_val) + ((uint32_t) src_val); // set new value cpu_ww(ctx, dst_reg, (uint16_t) (n & 0xFFFF)); // set flags cpu_wf(ctx, F_N | F_H | F_C, ( ((((dst_val & 0xFFF) + (src_val & 0xFFF)) > 0xFFF) ? F_H : 0) | ((n > 0xFFFF) ? F_C : 0) )); } static void add( gb_t * const ctx, const uint8_t n ) { // get old and new value const uint8_t o = cpu_rb(ctx, RB_A); const uint16_t v = o + n; // write value cpu_wb(ctx, RB_A, v); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( ((v & 0xFF) ? 0 : F_Z) | ((((o & 0x0F) + (n & 0x0F)) & 0xF0) ? F_H : 0) | ((v & 0x100) ? F_C : 0) )); } static void add_rb( gb_t * const ctx, const rb_t reg ) { add(ctx, cpu_rb(ctx, reg)); } static void add_d8( gb_t * const ctx, const uint16_t addr ) { add(ctx, mmu_rb(ctx, addr)); } static void add_hl_ptr( gb_t * const ctx ) { add(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); } static void add_sp_r8( gb_t * const ctx, const uint16_t addr ) { // get old and new value const uint16_t o = cpu_rw(ctx, RW_SP); const int8_t n = (int8_t) mmu_rb(ctx, addr); const uint16_t v = o + n; // write value cpu_ww(ctx, RW_SP, v); // FIXME: set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( ((((o & 0x0F) + (n & 0x0F)) & 0xF0) ? F_H : 0) | ((v & 0x100) ? F_C : 0) )); } static void ld_hl_sp_r8( gb_t * const ctx, const uint16_t ofs_addr ) { // get src values const uint16_t a = cpu_rw(ctx, RW_SP); const int8_t b = (int8_t) mmu_rb(ctx, ofs_addr); const uint16_t v = a + b; // write dst value cpu_ww(ctx, RW_HL, v); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (((a & 0xF0) != (v & 0xF0)) ? F_H : 0) | (((a & 0xF00) != (v & 0xF00)) ? F_C : 0) )); } static void adc( gb_t * const ctx, const uint8_t n ) { // get old value and carry flag const uint8_t o = cpu_rb(ctx, RB_A), c = FLAG(ctx, C) ? 1 : 0; const uint16_t v = o + n + c; // write value cpu_wb(ctx, RB_A, v); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( ((v & 0xFF) ? 0 : F_Z) | ((((o & 0x0F) + (n & 0x0F) + c) & 0xF0) ? F_H : 0) | ((v & 0x100) ? F_C : 0) )); } static void adc_rb( gb_t * const ctx, const rb_t reg ) { adc(ctx, cpu_rb(ctx, reg)); } static void adc_hl_ptr( gb_t * const ctx ) { adc(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); } static void adc_d8( gb_t * const ctx, const uint16_t addr ) { adc(ctx, mmu_rb(ctx, addr)); } static void sub( gb_t * const ctx, const uint8_t n ) { // get old and new value const uint8_t o = cpu_rb(ctx, RB_A), v = o - n; // write value cpu_wb(ctx, RB_A, v); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) | F_N | ((((o & 0x0F) - (n & 0x0F)) & 0xF0) ? F_H : 0) | ((n > o) ? F_C : 0) )); } static void sub_rb( gb_t * const ctx, const rb_t reg ) { sub(ctx, cpu_rb(ctx, reg)); } static void sub_hl_ptr( gb_t * const ctx ) { sub(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); } static void sub_d8( gb_t * const ctx, const uint16_t addr ) { sub(ctx, mmu_rb(ctx, addr)); } static void sbc( gb_t * const ctx, const uint8_t n ) { // get old and new value const uint8_t o = cpu_rb(ctx, RB_A), c = FLAG(ctx, C) ? 1 : 0, v = o - (n + c); // write value cpu_wb(ctx, RB_A, v); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) | F_N | ((((o & 0x0F) - (n & 0x0F)) & 0xF0) ? F_H : 0) | (((((uint16_t) n) + c) > o) ? F_C : 0) // FIXME: is this right for sub/sbc? )); } static void sbc_rb( gb_t * const ctx, const rb_t reg ) { sbc(ctx, cpu_rb(ctx, reg)); } static void sbc_hl_ptr( gb_t * const ctx ) { sbc(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); } static void sbc_d8( gb_t * const ctx, const uint16_t addr ) { sbc(ctx, mmu_rb(ctx, addr)); } static void and( gb_t * const ctx, const uint8_t val ) { // get value const uint8_t v = cpu_rb(ctx, RB_A) & val; // write value cpu_wb(ctx, RB_A, v); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) | F_H )); } static void and_rb( gb_t * const ctx, const rb_t reg ) { and(ctx, cpu_rb(ctx, reg)); } static void and_hl_ptr( gb_t * const ctx ) { and(ctx, mmu_rb(ctx, cpu_rb(ctx, RW_HL))); } static void and_d8( gb_t * const ctx, const uint16_t addr ) { and(ctx, mmu_rb(ctx, addr)); } static void xor( gb_t * const ctx, const uint8_t val ) { // get value const uint8_t v = cpu_rb(ctx, RB_A) ^ val; // write value cpu_wb(ctx, RB_A, v); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) )); } static void xor_rb( gb_t * const ctx, const rb_t reg ) { xor(ctx, cpu_rb(ctx, reg)); } static void xor_hl_ptr( gb_t * const ctx ) { xor(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); } static void xor_d8( gb_t * const ctx, const uint16_t addr ) { xor(ctx, mmu_rb(ctx, addr)); } static void or( gb_t * const ctx, const uint8_t val ) { const uint8_t v = cpu_rb(ctx, RB_A) | val; // write value cpu_wb(ctx, RB_A, v); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) )); } static void or_rb( gb_t * const ctx, const rb_t reg ) { or(ctx, cpu_rb(ctx, reg)); } static void or_hl_ptr( gb_t * const ctx ) { or(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); } static void or_d8( gb_t * const ctx, const uint16_t addr ) { or(ctx, mmu_rb(ctx, addr)); } static void cp( gb_t * const ctx, const uint8_t n ) { // get old and new value const uint8_t o = cpu_rb(ctx, RB_A), v = o - n; // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) | F_N | ((((o & 0x0F) - (n & 0x0F)) & 0xF0) ? F_H : 0) | ((n > o) ? F_C : 0) )); } static void cp_rb( gb_t * const ctx, const rb_t reg ) { cp(ctx, cpu_rb(ctx, reg)); } static void cp_hl_ptr( gb_t * const ctx ) { cp(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL))); } static void cp_d8( gb_t * const ctx, const uint16_t addr ) { cp(ctx, mmu_rb(ctx, addr)); } static void push_rw( gb_t * const ctx, const rw_t reg ) { // get sp const uint16_t sp = cpu_rw(ctx, RW_SP); // write to stack mmu_ww(ctx, sp - 2, cpu_rw(ctx, reg)); // decriment sp cpu_ww(ctx, RW_SP, sp - 2); } static void pop_rw( gb_t * const ctx, const rw_t reg ) { // get sp const uint16_t sp = cpu_rw(ctx, RW_SP); // read from sp cpu_ww(ctx, reg, mmu_rw(ctx, sp)); // increment sp cpu_ww(ctx, RW_SP, sp + 2); } static uint8_t rlc( gb_t * const ctx, const uint8_t o ) { // get carry bit and new value const uint8_t c = (o & 0x80) ? 1 : 0, n = ((o & 0x7F) << 1) + c; // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (n ? 0 : F_Z) | (c ? F_C : 0) )); // return new value return n; } static void rlc_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, rlc(ctx, cpu_rb(ctx, reg))); } static void rlc_hl( gb_t * const ctx ) { const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, rlc(ctx, mmu_rb(ctx, addr))); } static uint8_t rrc( gb_t * const ctx, const uint8_t o ) { // get carry bit and new value const uint8_t c = (o & 0x01) ? 1 : 0, n = (o >> 1) | (c ? 0x80 : 0); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (n ? 0 : F_Z) | (c ? F_C : 0) )); // return new value return n; } static void rrc_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, rrc(ctx, cpu_rb(ctx, reg))); } static void rrc_hl_ptr( gb_t * const ctx ) { const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, rrc(ctx, mmu_rb(ctx, addr))); } static uint8_t rl( gb_t * const ctx, const uint8_t o ) { const uint8_t n = (o << 1) + (FLAG(ctx, C) ? 1 : 0); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (n ? 0 : F_Z) | ((o & 0x80) ? F_C : 0) )); // return result return n; } static void rl_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, rl(ctx, cpu_rb(ctx, reg))); } static void rl_hl_ptr( gb_t * const ctx ) { const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, rl(ctx, mmu_rb(ctx, addr))); } static uint8_t rr( gb_t * const ctx, const uint8_t o ) { const uint8_t n = (FLAG(ctx, C) ? 0x80 : 0) | (o >> 1); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (n ? 0 : F_Z) | ((o & 0x01) ? F_C : 0) )); // return result return n; } static void rr_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, rr(ctx, cpu_rb(ctx, reg))); } static void rr_hl_ptr( gb_t * const ctx ) { const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, rr(ctx, mmu_rb(ctx, addr))); } static uint8_t sla( gb_t * const ctx, const uint8_t o ) { const uint8_t v = o << 1; // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) | ((o & 0x80) ? F_C : 0) )); // return value return v; } static void sla_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, sla(ctx, cpu_rb(ctx, reg))); } static void sla_hl_ptr( gb_t * const ctx ) { const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, sla(ctx, mmu_rb(ctx, addr))); } static uint8_t sra( gb_t * const ctx, const uint8_t o ) { const uint8_t v = ((o & 0x80) ? 0x80 : 0) | (o >> 1); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) | ((o & 0x01) ? F_C : 0) )); // return result return v; } static void sra_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, sra(ctx, cpu_rb(ctx, reg))); } static void sra_hl_ptr( gb_t * const ctx ) { const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, sra(ctx, mmu_rb(ctx, addr))); } static uint8_t srl( gb_t * const ctx, const uint8_t o ) { const uint8_t v = (o >> 1); // set flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) | ((o & 0x01) ? F_C : 0) )); // return result return v; } static void srl_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, srl(ctx, cpu_rb(ctx, reg))); } static void srl_hl_ptr( gb_t * const ctx ) { const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, srl(ctx, mmu_rb(ctx, addr))); } static void bit_rb( gb_t * const ctx, const rb_t reg, const uint8_t bit ) { // test bit const uint8_t v = cpu_rb(ctx, reg) & (bit ? (1 << bit) : 1); // set flags cpu_wf(ctx, F_Z | F_N | F_H, ( (v ? 0 : F_Z) | 0 | F_H )); } static void bit_hl( gb_t * const ctx, const uint8_t bit ) { // test bit const uint16_t addr = cpu_rb(ctx, RW_HL); const uint8_t v = mmu_rb(ctx, addr) & (bit ? (1 << bit) : 1); // set flags cpu_wf(ctx, F_Z | F_N | F_H, ( (v ? 0 : F_Z) | 0 | F_H )); } static void set_rb( gb_t * const ctx, const rb_t reg, const uint8_t bit ) { // get/update value cpu_wb(ctx, reg, cpu_rb(ctx, reg) | (bit ? (1 << bit) : 1)); } static void set_hl( gb_t * const ctx, const uint8_t bit ) { // get address const uint16_t addr = cpu_rw(ctx, RW_HL); // get/update value mmu_wb(ctx, addr, mmu_rb(ctx, addr) | (bit ? (1 << bit) : 1)); } static void res_rb( gb_t * const ctx, const rb_t reg, const uint8_t bit ) { // get/update value cpu_wb(ctx, reg, cpu_rb(ctx, reg) | ~(bit ? (1 << bit) : 1)); } static void res_hl( gb_t * const ctx, const uint8_t bit ) { // get address const uint16_t addr = cpu_rw(ctx, RW_HL); // get/update value mmu_wb(ctx, addr, mmu_rb(ctx, addr) | ~(bit ? (1 << bit) : 1)); } static uint8_t swap( gb_t * const ctx, const uint8_t v ) { // write flags cpu_wf(ctx, F_Z | F_N | F_H | F_C, ( (v ? 0 : F_Z) )); return ((v & (0x0F)) << 4) | ((v & 0xF0) >> 4); } static void swap_rb( gb_t * const ctx, const rb_t reg ) { cpu_wb(ctx, reg, swap(ctx, cpu_rb(ctx, reg))); } static void swap_hl_ptr( gb_t * const ctx ) { const uint16_t addr = cpu_rw(ctx, RW_HL); mmu_wb(ctx, addr, swap(ctx, mmu_rb(ctx, addr))); } static void jr( gb_t * const ctx, const uint16_t ofs_addr ) { // get offset const int8_t ofs = (int8_t) mmu_rb(ctx, ofs_addr); // jump cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + ofs); } static void rst( gb_t * const ctx, const uint16_t addr ) { // push pc push_rw(ctx, RW_PC); if (ctx->config && ctx->config->on_rst) { ctx->config->on_rst(ctx, addr); } // jump cpu_ww(ctx, RW_PC, addr); } static void call_a16( gb_t * const ctx, const uint16_t addr ) { // push pc push_rw(ctx, RW_PC); // jump cpu_ww(ctx, RW_PC, mmu_rw(ctx, addr)); } static void daa( gb_t * const ctx ) { UNUSED(ctx); // TODO: implement DAA } static bool gpu_is_active( const gb_t * const ctx ) { return ctx->gpu.lcdc & (1 << 7); } static void gpu_set_line( gb_t * const ctx, const uint8_t line ) { ctx->gpu.line = line; if (ctx->gpu.stat & (1 << 6) && (line == ctx->gpu.lyc)) { // lyc interrupt is enabled, trigger LCDC interrupt cpu_irq(ctx, IRQ_LCDC); } } static uint8_t gpu_get_mode( const gb_t * const ctx ) { return gpu_is_active(ctx) ? (ctx->gpu.mode & 0x3) : GPU_MODE_VBLANK; } static void gpu_set_mode( gb_t * const ctx, const uint8_t mode ) { ctx->gpu.mode = mode; if (ctx->config && ctx->config->on_gpu_set_mode) { ctx->config->on_gpu_set_mode(ctx, mode); } switch (mode & 0x03) { case GPU_MODE_OAM: if (ctx->gpu.stat & (1 << 5)) { // trigger LCDC interrupt cpu_irq(ctx, IRQ_LCDC); } break; case GPU_MODE_VRAM: // do nothing break; case GPU_MODE_HBLANK: if (ctx->gpu.stat & (1 << 3)) { // trigger LCDC interrupt cpu_irq(ctx, IRQ_LCDC); } if (ctx->config && ctx->config->on_hblank) { ctx->config->on_hblank(ctx); } break; case GPU_MODE_VBLANK: if (ctx->gpu.stat & (1 << 4)) { // trigger LCDC interrupt cpu_irq(ctx, IRQ_LCDC); } // trigger vblank interrupt cpu_irq(ctx, IRQ_VBLANK); if (gpu_is_active(ctx) && ctx->cpu.ime && (mmu_rb(ctx, PORT_IE) & 1)) { if (ctx->config && ctx->config->on_vblank) { ctx->config->on_vblank(ctx); } } break; } } static void gpu_oam_cache( gb_t * const ctx ) { if (!ctx->gpu.oam_dirty) { return; } // decode and cache oam for (uint8_t i = 0; i < 40; i++) { ctx->gpu.oam_cache[i].y = ctx->mmu.oam[4 * i + 0] - 10; ctx->gpu.oam_cache[i].x = ctx->mmu.oam[4 * i + 1] - 8; ctx->gpu.oam_cache[i].tile = ctx->mmu.oam[4 * i + 2]; const uint8_t flags = ctx->mmu.oam[4 * i + 3]; ctx->gpu.oam_cache[i].priority = flags & (1 << 7); ctx->gpu.oam_cache[i].y_flip = flags & (1 << 6); ctx->gpu.oam_cache[i].x_flip = flags & (1 << 5); ctx->gpu.oam_cache[i].palette = flags & (1 << 4); } // clear dirty flag ctx->gpu.oam_dirty = false; } static uint8_t bg_get_tile( gb_t * const ctx, const uint8_t ty, const uint8_t tx ) { // calculate tile offset return mmu_rb(ctx, ( // get bg tile map base // (lcdc & (1 << 3)) ((ctx->gpu.lcdc & (1 << 3)) ? 0x9C00 : 0x9800) + // calculate tile offset ty * 32 + tx )); } static uint16_t obj_get_tile_addr( gb_t * const ctx, const uint8_t tile ) { UNUSED(ctx); // base: 0x8000, tile is unsigned return 0x8000 + 16 * tile; } static uint16_t bg_get_tile_addr( gb_t * const ctx, const uint8_t ty, const uint8_t tx ) { // get tile const uint8_t tile = bg_get_tile(ctx, ty, tx); if (ctx->gpu.lcdc & (1 << 4)) { // base: 0x8000, tile is unsigned return 0x8000 + 16 * tile; } else { // base: 0x9000, tile is signed return 0x9000 + 16 * ((int8_t) tile); } } static uint8_t bg_get_color( gb_t * const ctx, const uint8_t sy, const uint8_t sx ) { // TODO: draw background const uint8_t y = (ctx->gpu.scy + sy) & 0xFF, ty = y >> 3, py = y - (ty << 3); const uint8_t x = (ctx->gpu.scx + sx) & 0xFF, tx = x >> 3, px = x - (tx << 3); // get tile data address const uint16_t addr = bg_get_tile_addr(ctx, ty, tx); // get tile data const uint16_t data = mmu_rw(ctx, addr + (2 * py)); // get bg palette entry const uint8_t p_ofs = ( ((data >> (8 + (7 - px)) & 0x01) << 1) | ((data >> (7 - px)) & 0x01) ); // get pixel color const uint8_t pc = (ctx->gpu.bgp >> (2 * p_ofs)) & 0x03; // convert from 0-3 to RGB switch (pc) { case 0: return 0xFF; case 1: return 0xC0; case 2: return 0x40; case 3: return 0x00; } // never reached return 0xA0; } static void gpu_draw_objs( gb_t * const ctx, const bool priority ) { for (uint8_t i = 0; i < 40; i++) { if ( // sprite has correct priority (ctx->gpu.oam_cache[i].priority == priority) && // sprite is on screen and visible BETWEEN(ctx->gpu.oam_cache[i].y, 0, 144) && BETWEEN(ctx->gpu.oam_cache[i].x, 0, 160) && // sprite is on current line BETWEEN(ctx->gpu.line, ctx->gpu.oam_cache[i].y, ctx->gpu.oam_cache[i].y + 8) ) { // get tile row data const uint16_t row = mmu_rw(ctx, ( // get tile data address obj_get_tile_addr(ctx, ctx->gpu.oam_cache[i].tile) + // calculate row offset within tile data (2 * (ctx->gpu.line - ctx->gpu.oam_cache[i].y)) )); for (uint8_t j = 0; j < 8; j++) { const int16_t sx = ctx->gpu.oam_cache[i].x + j; if (BETWEEN(sx, 0, 160)) { // get palette offset for pixel const uint8_t p_ofs = ( ((row >> (8 + (7 - j)) & 0x01) << 1) | ((row >> (7 - j)) & 0x01) ); // get pixel color if (p_ofs > 0) { // get object palette const uint8_t obp = ((ctx->gpu.oam_cache[i].palette) ? ctx->gpu.obp1 : ctx->gpu.obp0); // get pixel color const uint8_t pc = (obp >> (2 * p_ofs)) & 0x03; // calculate framebuffer offset const uint16_t fb_ofs = 3 * (160 * ctx->gpu.line + sx); // convert from 0-3 to RGB switch (pc) { case 0: ctx->gpu.fb[fb_ofs + 0] = 0xFF; ctx->gpu.fb[fb_ofs + 1] = 0xFF; ctx->gpu.fb[fb_ofs + 2] = 0xFF; break; case 1: ctx->gpu.fb[fb_ofs + 0] = 0xC0; ctx->gpu.fb[fb_ofs + 1] = 0xC0; ctx->gpu.fb[fb_ofs + 2] = 0xC0; break; case 2: ctx->gpu.fb[fb_ofs + 0] = 0x40; ctx->gpu.fb[fb_ofs + 1] = 0x40; ctx->gpu.fb[fb_ofs + 2] = 0x40; break; case 3: ctx->gpu.fb[fb_ofs + 0] = 0x00; ctx->gpu.fb[fb_ofs + 1] = 0x00; ctx->gpu.fb[fb_ofs + 2] = 0x00; break; } } } } } } } static void gpu_draw_line( gb_t * const ctx ) { if (gpu_is_active(ctx)) { gpu_oam_cache(ctx); if (ctx->gpu.lcdc & (1 << 1)) { // obj display is on, draw bg sprites gpu_draw_objs(ctx, true); } if (ctx->gpu.lcdc & 1) { // draw backgrond for (uint8_t i = 0; i < 160; i++) { // get bg pixel color const uint8_t c = bg_get_color(ctx, ctx->gpu.line, i); // populate framebuffer ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 0] = 0; // DEBUG ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 1] = c; ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 2] = 0; } } if (ctx->gpu.lcdc & (1 << 1)) { // obj display is on, draw fg sprites gpu_draw_objs(ctx, false); } } else { // write blank line for (uint8_t i = 0; i < 160; i++) { ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 0] = 0; // DEBUG ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 1] = 0xff; ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 2] = 0xff; } } } static void gpu_step( gb_t * const ctx, const uint16_t clock ) { // increment clock ctx->gpu.clock += clock; if (ctx->config && ctx->config->on_gpu_step) { ctx->config->on_gpu_step(ctx); } switch (gpu_get_mode(ctx)) { case GPU_MODE_OAM: if (ctx->gpu.clock >= 80) { // clear clock, set mode ctx->gpu.clock -= 80; gpu_set_mode(ctx, GPU_MODE_VRAM); } break; case GPU_MODE_VRAM: if (ctx->gpu.clock >= 172) { // clear clock, set mode ctx->gpu.clock -= 172; gpu_set_mode(ctx, GPU_MODE_HBLANK); } break; case GPU_MODE_HBLANK: if (ctx->gpu.clock >= 204) { // clear clock ctx->gpu.clock -= 204; // draw and increment line gpu_draw_line(ctx); gpu_set_line(ctx, ctx->gpu.line + 1); if (ctx->gpu.line < 143) { // set mode gpu_set_mode(ctx, GPU_MODE_OAM); } else { // increment frame number ctx->gpu.frame++; // set mode gpu_set_mode(ctx, GPU_MODE_VBLANK); } } break; case GPU_MODE_VBLANK: if (ctx->gpu.clock >= 204) { // clear clock ctx->gpu.clock -= 204; if (ctx->gpu.line < 153) { // increment line gpu_set_line(ctx, ctx->gpu.line + 1); } else { // reset line, set mode gpu_set_line(ctx, 0); gpu_set_mode(ctx, GPU_MODE_OAM); } } break; } } static void timer_step( gb_t * const ctx, const uint16_t clock ) { // increment div clock (high byte exposed via PORT_DIV) ctx->timer.div += clock; if (ctx->timer.tac & (1 << 2)) { const uint8_t shift = timer_get_shift(ctx); const uint32_t new_tima = ctx->timer.tima + clock; const uint8_t old_of = (ctx->timer.tima >> (shift + 8)) & 0xFF, new_of = (new_tima >> (shift + 8)) & 0xFF; if (new_of != old_of) { // reset TIMA register to value of TMA ctx->timer.tima = (ctx->timer.tma << shift); // trigger timer interrupt cpu_irq(ctx, IRQ_TIMER); if (ctx->config && ctx->config->on_timer) { // notify callback ctx->config->on_timer(ctx); } } } } static uint16_t cpu_step( gb_t * const ctx ) { if (ctx->cpu.state == GB_CPU_STATE_RUN) { // get pc, and current op const uint16_t old_pc = cpu_rw(ctx, RW_PC), op = mmu_rb(ctx, old_pc); uint16_t clock = 0; // exec op switch (op) { <%= switches['main'] %> case 0xCB: switch (mmu_rb(ctx, old_pc + 1)) { <%= switches['cb'] %> default: cpu_set_state(ctx, old_pc, GB_CPU_STATE_NOT_IMPLEMENTED); } break; default: cpu_set_state(ctx, old_pc, GB_CPU_STATE_NOT_IMPLEMENTED); } // increment cpu clock ctx->cpu.clock += clock; // return clock return clock; } else if (ctx->cpu.state == GB_CPU_STATE_HALT || ctx->cpu.state == GB_CPU_STATE_STOP) { // return 4 clock step return 4; } else { // return 0 clock step return 1; } } static void cpu_handle_interrupts( gb_t * const ctx ) { if (ctx->cpu.state == GB_CPU_STATE_RUN) { if (ctx->cpu.ime) { // get interrupt flags, masked against enabled interrupts const uint8_t iv = mmu_rb(ctx, PORT_IE) & mmu_rb(ctx, PORT_IF); bool done = false; for (uint8_t i = 0; !done && (i < 5); i++) { const uint8_t mask = i ? (1 << i) : 1; // has this interrupt been triggered? if (iv & mask) { // disable ime ctx->cpu.ime = false; // clear flag mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) ^ mask); // jump to handler rst(ctx, 0x0040 + (8 * i)); // FIXME: according to url below, this should take 5 cycles // (src: http://gbdev.gg8.se/wiki/articles/Interrupts) // break out of for loop done = true; } } } } else if (ctx->cpu.state == GB_CPU_STATE_HALT) { // get interrupt vector (masked against enabled interrupts) const uint8_t iv = mmu_rb(ctx, PORT_IE) & mmu_rb(ctx, PORT_IF); bool done = false; for (uint8_t i = 0; !done && (i < 5); i++) { const uint8_t mask = i ? (1 << i) : 1; // has this interrupt been triggered? if (iv & mask) { // if IME is set, then jump to interrupt handler // if IME is not set, then PC starts at first instruction // after HALT // (TCAGBD.pdf, 4.9) // wake cpu cpu_set_state(ctx, 0, GB_CPU_STATE_RUN); // FIXME: according to url below, this should take 5 cycles // (src: http://gbdev.gg8.se/wiki/articles/Interrupts) // break out of for loop done = true; if (ctx->cpu.ime) { // disable ime ctx->cpu.ime = false; // clear flag mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) ^ mask); // jump to handler rst(ctx, 0x0040 + (8 * i)); } } } } else if (ctx->cpu.state == GB_CPU_STATE_STOP) { // TODO: handle GB_CPU_STATE_STOP } else { } } void gb_step( gb_t * const ctx ) { // handle pending interrupts cpu_handle_interrupts(ctx); // advance cpu const uint16_t clock = cpu_step(ctx); // advance timer timer_step(ctx, clock); // advance gpu gpu_step(ctx, clock); } static const struct { const char * const name; const uint8_t len; } OPS[] = { <%= ops %> }; bool gb_disasm( gb_t * const ctx, char * const dst_buf, size_t * const dst_len ) { if (!dst_buf || !dst_len) { return false; } const uint8_t op = mmu_rb(ctx, cpu_rw(ctx, RW_PC)); const uint16_t ofs = (op == 0xCB) ? (255 + mmu_rb(ctx, cpu_rw(ctx, RW_PC) + 1)) : op; int len = -1; switch (OPS[ofs].len) { case 1: len = snprintf(dst_buf, *dst_len, "%s; %02x", OPS[ofs].name, op ); break; case 2: len = snprintf(dst_buf, *dst_len, "%s; %02x %02x", OPS[ofs].name, op, mmu_rb(ctx, cpu_rw(ctx, RW_PC) + 1) ); break; case 3: len = snprintf(dst_buf, *dst_len, "%s; %02x %02x %02x", OPS[ofs].name, op, mmu_rb(ctx, cpu_rw(ctx, RW_PC) + 1), mmu_rb(ctx, cpu_rw(ctx, RW_PC) + 2) ); break; default: len = snprintf(dst_buf, *dst_len, "%s", OPS[ofs].name); } return (len > 0) && (len < (int) *dst_len); } void gb_set_buttons( gb_t * const ctx, const uint8_t btns ) { if (ctx->mmu.btns != btns) { // set buttons ctx->mmu.btns = btns; // trigger p1 interrupt cpu_irq(ctx, IRQ_P1); } } void gb_frame( gb_t * const ctx ) { // get current frame const uint32_t frame = ctx->gpu.frame; // run until next frame while (ctx->gpu.frame == frame) { gb_step(ctx); } } const uint8_t * gb_get_frame( const gb_t * const ctx ) { return ctx->gpu.fb; } static void cpu_init( gb_t * const ctx ) { // init cpu registers // (src: TCAGBD.pdf, 3.2) // TODO: this varies by model (DGB/CGB/SGB/GBA/etc) ctx->cpu.rs[RW_AF] = 0x01B0; ctx->cpu.rs[RW_BC] = 0x0013; ctx->cpu.rs[RW_DE] = 0x00D8; ctx->cpu.rs[RW_HL] = 0x014D; ctx->cpu.rs[RW_SP] = 0xFFFE; ctx->cpu.rs[RW_PC] = 0x0100; // set cpu state cpu_set_state(ctx, 0, GB_CPU_STATE_RUN); } static void gpu_init( gb_t * const ctx ) { ctx->gpu.mode = GPU_MODE_VBLANK; ctx->gpu.line = 0; ctx->gpu.lcdc = 0x91; ctx->gpu.bgp = 0xFC; ctx->gpu.obp0 = 0xFF; ctx->gpu.obp1 = 0xFF; // flag oam as dirty ctx->gpu.oam_dirty = true; } void gb_init( gb_t * const ctx, const gb_config_t * const config, const uint8_t *rom, const uint32_t rom_size ) { // clear context memset(ctx, 0, sizeof(gb_t)); // save config ctx->config = config; // init cpu cpu_init(ctx); // init mmu ctx->mmu.rom = rom; ctx->mmu.rom_size = rom_size; // init gpu gpu_init(ctx); }