/* * Author: Max Regan * Last Modified: 11-17-2015 */ #include #include #include #include "gbemu/cpu.h" #include "common/common.h" #define CALC_H_ADD(a, b) ((((a) & 0xf) + ((b) & 0xf)) > 0xf) #define CALC_H_SUB(a, b) (((a) & 0xf) < ((b) & 0xf)) #define CARRY_MASK(idx) ((1 << idx) - 1) #define ADD_CARRY(a, b, idx) \ ((((a) & CARRY_MASK(idx)) + ((b) & CARRY_MASK(idx))) > CARRY_MASK(idx)) #define CALC_C_ADD_16(a, b) (0xffff - (a) < (b)) #define CALC_C_ADD_8(a, b) (0xff - (a) < (b)) #define CALC_C_SUB(a, b) ((a) < (b)) static void lr35902_handle_pending(struct lr35902_state *cpu); static int cpu_reg16_to_idx[NUM_LR35902_REGS_16] = { [LR35902_REG_BC] = 0, [LR35902_REG_DE] = 1, [LR35902_REG_HL] = 2, [LR35902_REG_AF] = 3, [LR35902_REG_PC] = 4, [LR35902_REG_SP] = 5, }; uint16_t lr35902_get_reg_16(const struct lr35902_state *cpu, lr35902_regs_16 reg) { ASSERT_MSG(reg >= 0 && reg < NUM_LR35902_REGS_16, "reg=%d\n", reg); return cpu->regs_16[cpu_reg16_to_idx[reg]]; } static int cpu_reg8_to_idx[NUM_LR35902_REGS_8] = { [LR35902_REG_A] = 6, [LR35902_REG_B] = 0, [LR35902_REG_C] = 1, [LR35902_REG_D] = 2, [LR35902_REG_E] = 3, [LR35902_REG_H] = 4, [LR35902_REG_L] = 5, [LR35902_REG_F] = 7, [LR35902_REG_HL_DEREF] = -1, }; uint8_t lr35902_get_reg_8(const struct lr35902_state *cpu, lr35902_regs_8 reg) { ASSERT(reg < NUM_LR35902_REGS_8); ASSERT(reg != LR35902_REG_HL_DEREF); return cpu->regs_8[cpu_reg8_to_idx[reg]]; } void lr35902_set_reg_16(struct lr35902_state *cpu, lr35902_regs_16 reg, uint16_t val) { ASSERT(reg < NUM_LR35902_REGS_16 && reg >= 0); cpu->regs_16[cpu_reg16_to_idx[reg]] = val; } void lr35902_set_reg_8(struct lr35902_state *cpu, lr35902_regs_8 reg, uint8_t val) { ASSERT(reg < NUM_LR35902_REGS_8 && reg >= 0); cpu->regs_8[cpu_reg8_to_idx[reg]] = val; } void lr35902_init(struct lr35902_state *cpu, struct gb_interrupt *interrupt, struct gb_memory *memory, const struct lr35902_ops *ops) { int i; cpu->interrupt = interrupt; cpu->memory = memory; cpu->undef_d3 = ops->undef_d3; cpu->int_state = LR35902_INT_OFF; cpu->stall_cycles = 0; cpu->halted = 0; for (i = 0; i < ARRAY_SIZE(cpu->regs_16); i++) { cpu->regs_16[i] = 0; } for (i = 0; i < ARRAY_SIZE(cpu->events); i++) { cpu->events[i].cycles = 0; cpu->events[i].run = NULL; } cpu->metrics.cycles = 0; cpu->metrics.retired_instrs = 0; cpu->metrics.mem_reads = 0; cpu->metrics.mem_writes = 0; } static const unsigned int op_extra_cycles[256] = { /* 0x0_ */ 0, 2, 1, 1, 0, 0, 1, 0, 4, 1, 1, 1, 0, 0, 1, 0, /* 0x1_ */ 0, 2, 1, 1, 0, 0, 1, 0, 2, 1, 1, 1, 0, 0, 1, 0, /* 0x2_ */ 1, 2, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, /* 0x3_ */ 1, 2, 1, 1, 2, 2, 2, 0, 1, 1, 1, 1, 0, 0, 1, 0, /* 0x4_ */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 0x5_ */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 0x6_ */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 0x7_ */ 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, //FIXME /* 0x0_ */ 0, 2, 1, 1, 0, 0, 1, 0, 4, 1, 1, 1, 0, 0, 1, 0, /* 0x1_ */ 0, 2, 1, 1, 0, 0, 1, 0, 2, 1, 1, 1, 0, 0, 1, 0, /* 0x2_ */ 1, 2, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, /* 0x3_ */ 1, 2, 1, 1, 2, 2, 2, 0, 1, 1, 1, 1, 0, 0, 1, 0, /* 0x4_ */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 0x5_ */ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 0x6_ */ 0, 0, 0, 0, 0, 3, 1, 3, 3, 3, 3, 3, 3, 3, 1, 3, /* 0x7_ */ 1, 1, 1, 1, 1, 1, 3, 1, 3, 3, 3, 3, 3, 3, 1, 3, }; static const unsigned int cb_extra_cycles[256] = { 0 }; /* TODO: optimize macros with temp variables so mem_read() doesn't expand multiple times */ #define INC_8(cpu, reg) \ do { \ (cpu)->nf = 0; \ (cpu)->hf = CALC_H_ADD(reg, 1); \ (reg)++; \ (cpu)->zf = (reg) == 0; \ } while (0) #define DEC_8(cpu, reg) \ do { \ (cpu)->nf = 1; \ (cpu)->hf = CALC_H_SUB(reg, 1); \ (reg)--; \ (cpu)->zf = (reg) == 0; \ } while (0) #define LD_D8(cpu, reg) \ do { \ (reg) = gb_mem_read((cpu)->memory, (cpu)->pc++); \ } while (0) #define LD_D16(cpu, reg) \ do { \ (reg) = gb_mem_read((cpu)->memory, (cpu)->pc++); \ (reg) |= (uint16_t) gb_mem_read((cpu)->memory, (cpu)->pc++) << 8; \ } while (0) #define ADD_8(cpu, dst, src) \ do { \ uint8_t _reg = src; \ (cpu)->nf = 0; \ (cpu)->hf = CALC_H_ADD((_reg), (dst)); \ (cpu)->cf = CALC_C_ADD_8((_reg), (dst)); \ (dst) += (_reg); \ (cpu)->zf = (dst) == 0; \ } while (0) #define ADD_16(cpu, dst, src) \ do { \ uint16_t _src = src; \ (cpu)->nf = 0; \ (cpu)->hf = (dst & 0xfff) + (_src & 0xfff) > 0xfff; \ (cpu)->cf = CALC_C_ADD_16(dst, _src); \ (dst) = _src + dst; \ } while (0) \ #define ADC_8(cpu, dst, src) \ do { \ uint16_t _dst = dst; \ uint16_t _src = src; \ cpu->nf = 0; \ cpu->hf = ((_src & 0xf) + (_dst & 0xf) + cpu->cf) > 0xf; \ _dst = _src + _dst + cpu->cf; \ cpu->cf = _dst > 0xff; \ cpu->zf = !(_dst & 0xff); \ (dst) = _dst; \ } while (0) #define SUB_8(cpu, dst, src) \ do { \ uint8_t _reg = src; \ int tmp; \ tmp = dst - _reg; \ (cpu)->cf = _reg > dst; \ (cpu)->nf = 1; \ (cpu)->hf = CALC_H_SUB(dst, _reg); \ (cpu)->zf = !tmp; \ dst = tmp; \ } while (0) #define SBC_8(cpu, dst, src) \ do { \ int tmp; \ uint8_t _reg = src; \ uint8_t cf = cpu->cf; \ tmp = (dst) - (_reg) - (cpu->cf); \ (cpu)->cf = tmp < 0; \ (cpu)->nf = 1; \ (cpu)->hf = ((dst & 0xf) - (_reg & 0xf) - cf) < 0 ; \ (dst) = (tmp); \ (cpu)->zf = dst == 0; \ } while (0) #define AND_8(cpu, dst, src) \ do { \ uint8_t _reg = src; \ (cpu)->nf = 0; \ (cpu)->hf = 1; \ (cpu)->cf = 0; \ (dst) &= (_reg); \ (cpu)->zf = ((dst) == 0); \ } while (0) #define XOR_8(cpu, dst, src) \ do { \ uint8_t _reg = src; \ (cpu)->nf = 0; \ (cpu)->hf = 0; \ (cpu)->cf = 0; \ (dst) ^= (_reg); \ (cpu)->zf = ((dst) == 0); \ } while (0) #define OR_8(cpu, dst, src) \ do { \ uint8_t _reg = src; \ (cpu)->nf = 0; \ (cpu)->hf = 0; \ (cpu)->cf = 0; \ (dst) |= (_reg); \ (cpu)->zf = ((dst) == 0); \ } while (0) #define CP_8(cpu, dst, src) \ do { \ uint8_t _tmp; \ uint8_t _dst = dst; \ uint8_t _src = src; \ (cpu)->nf = 1; \ (cpu)->hf = CALC_H_SUB((_dst), (_src)); \ (cpu)->cf = CALC_C_SUB((_dst), (_src)); \ _tmp = (_dst) - (_src); \ (cpu)->zf = ((_tmp) == 0); \ } while (0) #define JR_8(cpu) \ do { \ val_16 = gb_mem_read((cpu)->memory, cpu->pc++); \ /* sign-extend */ \ val_16 |= GET_BIT(val_16, 7) ? 0xff00 : 0; \ cpu->pc += val_16; \ } while (0) #define POP_16(cpu, dst) \ do { \ (dst) = gb_mem_read((cpu)->memory, (cpu)->sp++); \ (dst) |= (uint16_t) gb_mem_read((cpu)->memory, (cpu)->sp++) << 8; \ } while (0) #define PUSH_16(cpu, src) \ do { \ gb_mem_write(cpu->memory, --cpu->sp, src >> 8); \ gb_mem_write(cpu->memory, --cpu->sp, src); \ } while (0) #define CALL(cpu) \ do { \ uint16_t pc_base; \ uint16_t old_pc = cpu->pc; \ pc_base = gb_mem_read(cpu->memory, cpu->pc++); \ pc_base |= (uint16_t) gb_mem_read(cpu->memory, cpu->pc++) << 8; \ PUSH_16(cpu, cpu->pc); \ cpu->pc = pc_base; \ } while (0) #define RET(cpu) \ do { \ uint16_t old_pc = cpu->pc; \ POP_16(cpu, cpu->pc); \ } while (0) #define RST(cpu, n) \ do { \ PUSH_16(cpu, cpu->pc); \ (cpu)->pc = (n); \ } while (0) #define BIT(cpu, reg, bit) \ do { \ (cpu)->zf = !GET_BIT(reg, bit); \ (cpu)->nf = 0; \ (cpu)->hf = 1; \ } while (0) #define RES(reg, bit) \ do { \ CLR_BIT(reg, bit); \ } while (0) #define SET(reg, bit) \ do { \ SET_BIT(reg, bit); \ } while (0) #define RL(cpu, reg) \ do { \ uint8_t ci = (cpu)->cf; \ uint8_t tmp = reg; \ (cpu)->nf = 0; \ (cpu)->hf = 0; \ (cpu)->cf = GET_BIT(tmp, 7); \ tmp = tmp << 1; \ (tmp) |= ci; \ (cpu)->zf = (tmp) == 0; \ reg = tmp; \ } while (0) #define RLC(cpu, reg) \ do { \ uint8_t tmp = reg; \ (cpu)->nf = 0; \ (cpu)->hf = 0; \ (cpu)->cf = GET_BIT(tmp, 7); \ tmp = tmp << 1; \ tmp |= (cpu)->cf; \ (cpu)->zf = (tmp) == 0; \ reg = tmp; \ } while (0) #define RRC(cpu, reg) \ do { \ cpu->cf = GET_BIT(reg, 0); \ cpu->nf = 0; \ cpu->hf = 0; \ (reg) >>= 1; \ WRITE_BIT(reg, 7, cpu->cf); \ cpu->zf = (reg == 0); \ } while (0) #define SLA(cpu, reg) \ do { \ cpu->cf = GET_BIT(reg, 7); \ reg <<= 1; \ cpu->nf = 0; \ cpu->zf = !reg; \ cpu->hf = 0; \ } while (0) #define SRL(cpu, reg) \ do { \ cpu->cf = GET_BIT(reg, 0); \ reg >>= 1; \ cpu->nf = 0; \ cpu->zf = !reg; \ cpu->hf = 0; \ } while (0) #define RR(cpu, reg) \ do { \ uint8_t ci = cpu->cf; \ cpu->cf = GET_BIT(reg, 0); \ reg >>= 1; \ WRITE_BIT(reg, 7, ci); \ cpu->nf = 0; \ cpu->zf = !reg; \ cpu->hf = 0; \ } while (0) #define SRA(cpu, reg) \ do { \ uint8_t val = GET_BIT(reg, 7); \ cpu->cf = GET_BIT(reg, 0); \ cpu->nf = 0; \ cpu->hf = 0; \ reg = (val << 7) | (reg >> 1); \ cpu->zf = !reg; \ } while (0) \ #define SWAP(cpu, reg) \ do { \ uint8_t tmp = reg << 4; \ tmp |= reg >> 4; \ (cpu)->zf = tmp == 0; \ (cpu)->hf = 0; \ (cpu)->nf = 0; \ (cpu)->cf = 0; \ reg = tmp; \ } while (0) int lr35902_cycle(struct lr35902_state *cpu) { uint8_t inst; uint8_t val; uint16_t val_16; uint8_t *reg = NULL; int cycles; cpu->metrics.retired_instrs++; inst = gb_mem_read(cpu->memory, cpu->pc++); cycles = op_extra_cycles[inst]; switch (inst) { case 0x00: /* NOP */ break; case 0x01: /* LD BC, d16 */ LD_D16(cpu, cpu->bc); break; case 0x02: /* LD (BC), A */ gb_mem_write(cpu->memory, cpu->bc, cpu->a); break; case 0x03: /* INC BC */ cpu->bc++; break; case 0x04: /* INC B */ INC_8(cpu, cpu->b); break; case 0x05: /* DEC B */ DEC_8(cpu, cpu->b); break; case 0x06: /* LD B, d8 */ LD_D8(cpu, cpu->b); break; case 0x07: /* RLCA */ cpu->cf = GET_BIT(cpu->a, 7); cpu->nf = 0; cpu->zf = 0; cpu->hf = 0; cpu->a <<= 1; WRITE_BIT(cpu->a, 0, cpu->cf); break; case 0x08: /* LD (a16), SP */ val_16 = gb_mem_read(cpu->memory, cpu->pc++); val_16 |= gb_mem_read(cpu->memory, cpu->pc++) << 8; gb_mem_write(cpu->memory, val_16, cpu->sp & 0xff); gb_mem_write(cpu->memory, val_16 + 1, (cpu->sp >> 8) & 0xff); break; case 0x09: /* ADD HL, BC */ ADD_16(cpu, cpu->hl, cpu->bc); break; case 0x0a: /* LD A, (BC) */ cpu->a = gb_mem_read(cpu->memory, cpu->bc); break; case 0x0b: /* DEC, BC */ cpu->bc--; break; case 0x0c: /* INC C */ INC_8(cpu, cpu->c); break; case 0x0d: /* DEC C */ DEC_8(cpu, cpu->c); break; case 0x0e: /* LD C, d8 */ LD_D8(cpu, cpu->c); break; case 0x0f: /* RRCA */ RRC(cpu, cpu->a); cpu->zf = 0; break; case 0x10: /* STOP */ ASSERT(0); //TODO: Implement me break; case 0x11: /* LD DE, d16 */ LD_D16(cpu, cpu->de); break; case 0x12: /* LD (DE), A */ gb_mem_write(cpu->memory, cpu->de, cpu->a); break; case 0x13: /* INC DE */ cpu->de++; break; case 0x14: /* INC D */ INC_8(cpu, cpu->d); break; case 0x15: /* DEC D */ DEC_8(cpu, cpu->d); break; case 0x16: /* LD D, d8 */ LD_D8(cpu, cpu->d); break; case 0x17: /* RLA */ val = GET_BIT(cpu->a, 7); cpu->nf = 0; cpu->zf = 0; cpu->hf = 0; cpu->a = (cpu->a << 1) | cpu->cf; cpu->cf = val; break; case 0x18: /* JR r8 */ JR_8(cpu); break; case 0x19: /* ADD HL, DE */ ADD_16(cpu, cpu->hl, cpu->de); break; case 0x1a: /* LD A, (DE) */ cpu->a = gb_mem_read(cpu->memory, cpu->de); break; case 0x1b: /* DEC DE */ cpu->de--; break; case 0x1c: /* INC E */ INC_8(cpu, cpu->e); break; case 0x1d: /* DEC E */ DEC_8(cpu, cpu->e); break; case 0x1e: /* LD E, d8 */ LD_D8(cpu, cpu->e); break; case 0x1f: /* RRA */ val = GET_BIT(cpu->a, 0); cpu->nf = 0; cpu->zf = 0; cpu->hf = 0; cpu->a = (cpu->cf << 7) | (cpu->a >> 1) ; cpu->cf = val; break; case 0x20: /* JR NZ, r8 */ if (!cpu->zf) { JR_8(cpu); } else { cpu->pc++; } break; case 0x21: /* LD HL, d16 */ LD_D16(cpu, cpu->hl); break; case 0x22: /* LD (HL+), A */ gb_mem_write(cpu->memory, cpu->hl++, cpu->a); break; case 0x23: /* INC HL */ cpu->hl++; break; case 0x24: /* INC H */ INC_8(cpu, cpu->h); break; case 0x25: /* DEC H */ DEC_8(cpu, cpu->h); break; case 0x26: /* LD h, d8 */ LD_D8(cpu, cpu->h); break; case 0x27: /* DAA */ { /* The internet agrees that this opcode is terrible. I've * copied the same implementation (almost) everyone else * has. */ uint16_t a = cpu->a; if (!cpu->nf) { if (cpu->hf || ((a & 0xf) > 9)) { a += 0x6; } if (cpu->cf || (a > 0x9f)) { a += 0x60; } } else { if (cpu->hf) { a -= 0x6; a &= 0xff; } if (cpu->cf) { a -= 0x60; } } if (GET_BIT(a,8)) { cpu->cf = 1; } cpu->hf = 0; cpu->a = a; cpu->zf = !cpu->a; break; } case 0x28: /* JR Z, r8 */ if (cpu->zf) { JR_8(cpu); } else { cpu->pc++; } break; case 0x29: /* ADD HL, HL */ ADD_16(cpu, cpu->hl, cpu->hl); break; case 0x2a: /* LD A, (HL+) */ cpu->a = gb_mem_read(cpu->memory, cpu->hl++); break; case 0x2b: /* DEC HL */ cpu->hl--; break; case 0x2c: /* INC L */ INC_8(cpu, cpu->l); break; case 0x2d: /* DEC L */ DEC_8(cpu, cpu->l); break; case 0x2e: /* LD l, d8 */ LD_D8(cpu, cpu->l); break; case 0x2f: /* CPL */ cpu->nf = 1; cpu->hf = 1; cpu->a = ~cpu->a; break; case 0x30: /* JR NC, r8 */ if (!cpu->cf) { JR_8(cpu); } else { cpu->pc++; } break; case 0x31: /* LD SP, d16 */ LD_D16(cpu, cpu->sp); break; case 0x32: /* LD (HL-), A */ gb_mem_write(cpu->memory, cpu->hl--, cpu->a); break; case 0x33: /* INC SP */ cpu->sp++; break; case 0x34: /* INC (HL) */ val = gb_mem_read(cpu->memory, cpu->hl); cpu->nf = 0; cpu->hf = CALC_H_ADD(val, 1); val++; gb_mem_write(cpu->memory, cpu->hl, val); cpu->zf = (val == 0); break; case 0x35: /* DEC (HL) */ val = gb_mem_read(cpu->memory, cpu->hl); cpu->hf = CALC_H_SUB(val, 1); cpu->zf = (val == 0); cpu->nf = 1; val--; gb_mem_write(cpu->memory, cpu->hl, val); break; case 0x36: /* LD (HL), d8 */ val = gb_mem_read(cpu->memory, cpu->pc++); gb_mem_write(cpu->memory, cpu->hl, val); break; case 0x37: /* SCF */ cpu->nf = 0; cpu->hf = 0; cpu->cf = 1; break; case 0x38: /* JR C, r8*/ if (cpu->cf) { JR_8(cpu); } else { cpu->pc++; } break; case 0x39: /* ADD HL,SP */ ADD_16(cpu, cpu->hl, cpu->sp); break; case 0x3a: /* LD A, (HL-) */ cpu->a = gb_mem_read(cpu->memory, cpu->hl--); break; case 0x3b: /* DEC SP */ cpu->sp--; break; case 0x3c: /* INC A */ INC_8(cpu, cpu->a); break; case 0x3d: /* DEC A */ DEC_8(cpu, cpu->a); break; case 0x3e: /* LD A, d8 */ LD_D8(cpu, cpu->a); break; case 0x3f: /* CCF */ cpu->nf = 0; cpu->hf = 0; cpu->cf = !cpu->cf; break; case 0x40: /* LD B,B */ break; case 0x41: /* LD B,C */ cpu->b = cpu->c; break; case 0x42: /* LD B,D */ cpu->b = cpu->d; break; case 0x43: /* LD B,E */ cpu->b = cpu->e; break; case 0x44: /* LD B,H */ cpu->b = cpu->h; break; case 0x45: /* LD B,L */ cpu->b = cpu->l; break; case 0x46: /* LD B,(HL) */ cpu->b = gb_mem_read(cpu->memory, cpu->hl); break; case 0x47: /* LD B,A */ cpu->b = cpu->a; break; case 0x48: /* LD C,B */ cpu->c = cpu->b; break; case 0x49: /* LD C,C */ break; case 0x4a: /* LD C,D */ cpu->c = cpu->d; break; case 0x4b: /* LD C,E */ cpu->c = cpu->e; break; case 0x4c: /* LD C,H */ cpu->c = cpu->h; break; case 0x4d: /* LD C,L */ cpu->c = cpu->l; break; case 0x4e: /* LD C,(HL) */ cpu->c = gb_mem_read(cpu->memory, cpu->hl); break; case 0x4f: /* LD C,A */ cpu->c = cpu->a; break; case 0x50: /* LD D,B */ cpu->d = cpu->b; break; case 0x51: /* LD D,C */ cpu->d = cpu->c; break; case 0x52: /* LD D,D */ break; case 0x53: /* LD D,E */ cpu->d = cpu->e; break; case 0x54: /* LD D,H */ cpu->d = cpu->h; break; case 0x55: /* LD D,L */ cpu->d = cpu->l; break; case 0x56: /* LD D,(HL) */ cpu->d = gb_mem_read(cpu->memory, cpu->hl); break; case 0x57: /* LD D,A */ cpu->d = cpu->a; break; case 0x58: /* LD E,B */ cpu->e = cpu->b; break; case 0x59: /* LD E,C */ cpu->e = cpu->c; break; case 0x5a: /* LD E,D */ cpu->e = cpu->d; break; case 0x5b: /* LD E,E */ break; case 0x5c: /* LD E,H */ cpu->e = cpu->h; break; case 0x5d: /* LD E,L */ cpu->e = cpu->l; break; case 0x5e: /* LD E,(HL) */ cpu->e = gb_mem_read(cpu->memory, cpu->hl); break; case 0x5f: /* LD E,A */ cpu->e = cpu->a; break; case 0x60: /* LD H,B */ cpu->h = cpu->b; break; case 0x61: /* LD H,C */ cpu->h = cpu->c; break; case 0x62: /* LD H,D */ cpu->h = cpu->d; break; case 0x63: /* LD H,E */ cpu->h = cpu->e; break; case 0x64: /* LD H,H */ break; case 0x65: /* LD H,L */ cpu->h = cpu->l; break; case 0x66: /* LD H,(HL) */ cpu->h = gb_mem_read(cpu->memory, cpu->hl); break; case 0x67: /* LD H,A */ cpu->h = cpu->a; break; case 0x68: /* LD L,B */ cpu->l = cpu->b; break; case 0x69: /* LD L,C */ cpu->l = cpu->c; break; case 0x6a: /* LD L,D */ cpu->l = cpu->d; break; case 0x6b: /* LD L,E */ cpu->l = cpu->e; break; case 0x6c: /* LD L,H */ cpu->l = cpu->h; break; case 0x6d: /* LD L,L */ break; case 0x6e: /* LD L,(HL) */ cpu->l = gb_mem_read(cpu->memory, cpu->hl); break; case 0x6f: /* LD L,A */ cpu->l = cpu->a; break; case 0x70: /* LD (HL),B */ gb_mem_write(cpu->memory, cpu->hl, cpu->b); break; case 0x71: /* LD (HL),C */ gb_mem_write(cpu->memory, cpu->hl, cpu->c); break; case 0x72: /* LD (HL),D */ gb_mem_write(cpu->memory, cpu->hl, cpu->d); break; case 0x73: /* LD (HL),E */ gb_mem_write(cpu->memory, cpu->hl, cpu->e); break; case 0x74: /* LD (HL),H */ gb_mem_write(cpu->memory, cpu->hl, cpu->h); break; case 0x75: /* LD (HL),L */ gb_mem_write(cpu->memory, cpu->hl, cpu->l); break; case 0x76: /* HALT */ cpu->halted = 1; break; case 0x77: /* LD (HL),A */ gb_mem_write(cpu->memory, cpu->hl, cpu->a); break; case 0x78: /* LD A,B */ cpu->a = cpu->b; break; case 0x79: /* LD A,C */ cpu->a = cpu->c; break; case 0x7a: /* LD A,D */ cpu->a = cpu->d; break; case 0x7b: /* LD A,E */ cpu->a = cpu->e; break; case 0x7c: /* LD A,H */ cpu->a = cpu->h; break; case 0x7d: /* LD A,L */ cpu->a = cpu->l; break; case 0x7e: /* LD A,(HL) */ cpu->a = gb_mem_read(cpu->memory, cpu->hl); break; case 0x7f: /* LD A,A */ break; case 0x80: /* ADD A,B */ ADD_8(cpu, cpu->a, cpu->b); break; case 0x81: /* ADD A,C */ ADD_8(cpu, cpu->a, cpu->c); break; case 0x82:/* ADD A,D */ ADD_8(cpu, cpu->a, cpu->d); break; case 0x83:/* ADD A,E */ ADD_8(cpu, cpu->a, cpu->e); break; case 0x84:/* ADD A,H */ ADD_8(cpu, cpu->a, cpu->h); break; case 0x85:/* ADD A,l */ ADD_8(cpu, cpu->a, cpu->l); break; case 0x86: /* ADD A,(HL) */ ADD_8(cpu, cpu->a, gb_mem_read(cpu->memory, cpu->hl)); break; case 0x87: /* ADD A,A */ ADD_8(cpu, cpu->a, cpu->a); break; case 0x88: /* ADC A,B */ ADC_8(cpu, cpu->a, cpu->b); break; case 0x89: /* ADC A,C */ ADC_8(cpu, cpu->a, cpu->c); break; case 0x8a:/* ADC A,D */ ADC_8(cpu, cpu->a, cpu->d); break; case 0x8b:/* ADC A,E */ ADC_8(cpu, cpu->a, cpu->e); break; case 0x8c:/* ADC A,H */ ADC_8(cpu, cpu->a, cpu->h); break; case 0x8d:/* ADC A,L */ ADC_8(cpu, cpu->a, cpu->l); break; case 0x8e: /* ADC A,(HL) */ ADC_8(cpu, cpu->a, gb_mem_read(cpu->memory, cpu->hl)); break; case 0x8f: /* ADC A,A */ ADC_8(cpu, cpu->a, cpu->a); break; case 0x90: /* SUB A,B */ SUB_8(cpu, cpu->a, cpu->b); break; case 0x91: /* SUB A,C */ SUB_8(cpu, cpu->a, cpu->c); break; case 0x92: /* SUB A,D */ SUB_8(cpu, cpu->a, cpu->d); break; case 0x93: /* SUB A,E */ SUB_8(cpu, cpu->a, cpu->e); break; case 0x94: /* SUB A,H */ SUB_8(cpu, cpu->a, cpu->h); break; case 0x95: /* SUB A,L */ SUB_8(cpu, cpu->a, cpu->l); break; case 0x96: /* SUB A,(HL) */ SUB_8(cpu, cpu->a, gb_mem_read(cpu->memory, cpu->hl)); break; case 0x97: /* SUB A,A */ SUB_8(cpu, cpu->a, cpu->a); break; case 0x98: /* SBC A, B */ SBC_8(cpu, cpu->a, cpu->b); break; case 0x99: /* SBC A, C */ SBC_8(cpu, cpu->a, cpu->c); break; case 0x9a: /* SBC A, D */ SBC_8(cpu, cpu->a, cpu->d); break; case 0x9b: /* SBC A, E */ SBC_8(cpu, cpu->a, cpu->e); break; case 0x9c: /* SBC A, H */ SBC_8(cpu, cpu->a, cpu->h); break; case 0x9d: /* SBC A, L */ SBC_8(cpu, cpu->a, cpu->l); break; case 0x9e: /* SBC A, (HL) */ SBC_8(cpu, cpu->a, gb_mem_read(cpu->memory, cpu->hl)); break; case 0x9f: /* SBC A, A */ SBC_8(cpu, cpu->a, cpu->a); break; case 0xa0: /* AND A, B */ AND_8(cpu, cpu->a, cpu->b); break; case 0xa1: /* AND A, C */ AND_8(cpu, cpu->a, cpu->c); break; case 0xa2: /* AND A, D */ AND_8(cpu, cpu->a, cpu->d); break; case 0xa3: /* AND A, E */ AND_8(cpu, cpu->a, cpu->e); break; case 0xa4: /* AND A, H */ AND_8(cpu, cpu->a, cpu->h); break; case 0xa5: /* AND A, L */ AND_8(cpu, cpu->a, cpu->l); break; case 0xa6: /* AND A, (HL) */ AND_8(cpu, cpu->a, gb_mem_read(cpu->memory, cpu->hl)); break; case 0xa7: /* AND A, A */ AND_8(cpu, cpu->a, cpu->a); break; case 0xa8: /* XOR A, B */ XOR_8(cpu, cpu->a, cpu->b); break; case 0xa9: /* XOR A, C */ XOR_8(cpu, cpu->a, cpu->c); break; case 0xaa: /* XOR A, D */ XOR_8(cpu, cpu->a, cpu->d); break; case 0xab: /* XOR A, E */ XOR_8(cpu, cpu->a, cpu->e); break; case 0xac: /* XOR A, H */ XOR_8(cpu, cpu->a, cpu->h); break; case 0xad: /* XOR A, L */ XOR_8(cpu, cpu->a, cpu->l); break; case 0xae: /* XOR A, (HL) */ XOR_8(cpu, cpu->a, gb_mem_read(cpu->memory, cpu->hl)); break; case 0xaf: /* XOR A, A */ XOR_8(cpu, cpu->a, cpu->a); break; case 0xb0: /* OR A, B */ OR_8(cpu, cpu->a, cpu->b); break; case 0xb1: /* OR A, C */ OR_8(cpu, cpu->a, cpu->c); break; case 0xb2: /* OR A, D */ OR_8(cpu, cpu->a, cpu->d); break; case 0xb3: /* OR A, E */ OR_8(cpu, cpu->a, cpu->e); break; case 0xb4: /* OR A, H */ OR_8(cpu, cpu->a, cpu->h); break; case 0xb5: /* OR A, L */ OR_8(cpu, cpu->a, cpu->l); break; case 0xb6: /* OR A, (HL) */ OR_8(cpu, cpu->a, gb_mem_read(cpu->memory, cpu->hl)); break; case 0xb7: /* OR A, A */ OR_8(cpu, cpu->a, cpu->a); break; case 0xb8: /* CP A, B */ CP_8(cpu, cpu->a, cpu->b); break; case 0xb9: /* CP A, C */ CP_8(cpu, cpu->a, cpu->c); break; case 0xba: /* CP A, D */ CP_8(cpu, cpu->a, cpu->d); break; case 0xbb: /* CP A, E */ CP_8(cpu, cpu->a, cpu->e); break; case 0xbc: /* CP A, H */ CP_8(cpu, cpu->a, cpu->h); break; case 0xbd: /* CP A, L */ CP_8(cpu, cpu->a, cpu->l); break; case 0xbe: /* CP A, (HL) */ CP_8(cpu, cpu->a, gb_mem_read(cpu->memory, cpu->hl)); break; case 0xbf: /* CP A, A */ CP_8(cpu, cpu->a, cpu->a); break; case 0xc0: /* RET NZ */ if (!cpu->zf) { RET(cpu); } break; case 0xc1: /* POP BC */ POP_16(cpu, cpu->bc); break; case 0xc2: /* JP NZ, a16 */ val_16 = gb_mem_read(cpu->memory, cpu->pc++); val_16 |= ((uint16_t) gb_mem_read(cpu->memory, cpu->pc++) << 8); if (!cpu->zf) { cpu->pc = val_16; } break; case 0xc3: /* JP a16 */ val_16 = gb_mem_read(cpu->memory, cpu->pc++); val_16 |= ((uint16_t) gb_mem_read(cpu->memory, cpu->pc++) << 8); cpu->pc = val_16; break; case 0xc4: /* CALL NZ */ if (!cpu->zf) { CALL(cpu); } else { cpu->pc += 2; } break; case 0xc5: /* PUSH BC */ PUSH_16(cpu, cpu->bc); break; case 0xc6: /* ADD A, d8 */ val = gb_mem_read(cpu->memory, cpu->pc++); ADD_8(cpu, cpu->a, val); break; case 0xc7: /* RST 00 */ RST(cpu, 0); break; case 0xc8: /* RET Z */ if (cpu->zf) { RET(cpu); } break; case 0xc9: /* RET */ RET(cpu); break; case 0xca: /* JP z, a16 */ val_16 = gb_mem_read(cpu->memory, cpu->pc++); val_16 |= ((uint16_t) gb_mem_read(cpu->memory, cpu->pc++) << 8); if (cpu->zf) { cpu->pc = val_16; } break; case 0xcb: inst = gb_mem_read(cpu->memory, cpu->pc++); cycles = cb_extra_cycles[inst]; switch (inst) { case 0x00: RLC(cpu, cpu->b); break; case 0x01: RLC(cpu, cpu->c); break; case 0x02: RLC(cpu, cpu->d); break; case 0x03: RLC(cpu, cpu->e); break; case 0x04: RLC(cpu, cpu->h); break; case 0x05: RLC(cpu, cpu->l); break; case 0x06: val = gb_mem_read(cpu->memory, cpu->hl); RLC(cpu, val); gb_mem_write(cpu->memory, cpu->hl, val); break; case 0x07: RLC(cpu, cpu->a); break; case 0x08: RRC(cpu, cpu->b); break; case 0x09: RRC(cpu, cpu->c); break; case 0x0a: RRC(cpu, cpu->d); break; case 0x0b: RRC(cpu, cpu->e); break; case 0x0c: RRC(cpu, cpu->h); break; case 0x0d: RRC(cpu, cpu->l); break; case 0x0e: val = gb_mem_read(cpu->memory, cpu->hl); RLC(cpu, val); gb_mem_write(cpu->memory, cpu->hl, val); break; case 0x0f: RRC(cpu, cpu->a); break; case 0x10: RL(cpu, cpu->b); break; case 0x11: RL(cpu, cpu->c); break; case 0x12: RL(cpu, cpu->d); break; case 0x13: RL(cpu, cpu->e); break; case 0x14: RL(cpu, cpu->h); break; case 0x15: RL(cpu, cpu->l); break; case 0x16: ASSERT(0); break; case 0x17: RL(cpu, cpu->a); break; case 0x18: RR(cpu, cpu->b); break; case 0x19: RR(cpu, cpu->c); break; case 0x1a: RR(cpu, cpu->d); break; case 0x1b: RR(cpu, cpu->e); break; case 0x1c: RR(cpu, cpu->h); break; case 0x1d: RR(cpu, cpu->l); break; case 0x1e: ASSERT(0); break; case 0x1f: RR(cpu, cpu->a); break; case 0x20: SLA(cpu, cpu->b); break; case 0x21: SLA(cpu, cpu->c); break; case 0x22: SLA(cpu, cpu->d); break; case 0x23: SLA(cpu, cpu->e); break; case 0x24: SLA(cpu, cpu->h); break; case 0x25: SLA(cpu, cpu->l); break; case 0x26: val = gb_mem_read(cpu->memory, cpu->hl); SLA(cpu, val); gb_mem_write(cpu->memory, cpu->hl, val); break; case 0x27: SLA(cpu, cpu->a); break; case 0x28: SRA(cpu, cpu->b); break; case 0x29: SRA(cpu, cpu->c); break; case 0x2a: SRA(cpu, cpu->d); break; case 0x2b: SRA(cpu, cpu->e); break; case 0x2c: SRA(cpu, cpu->h); break; case 0x2d: SRA(cpu, cpu->l); break; case 0x2e: val = gb_mem_read(cpu->memory, cpu->hl); SRA(cpu, val); gb_mem_write(cpu->memory, cpu->hl, val); break; case 0x2f: SRA(cpu, cpu->a); break; case 0x30: SWAP(cpu, cpu->b); break; case 0x31: SWAP(cpu, cpu->c); break; case 0x32: SWAP(cpu, cpu->d); break; case 0x33: SWAP(cpu, cpu->e); break; case 0x34: SWAP(cpu, cpu->h); break; case 0x35: SWAP(cpu, cpu->l); break; case 0x36: ASSERT(0); break; case 0x37: SWAP(cpu, cpu->a); break; case 0x38: SRL(cpu, cpu->b); break; case 0x39: SRL(cpu, cpu->c); break; case 0x3a: SRL(cpu, cpu->d); break; case 0x3b: SRL(cpu, cpu->e); break; case 0x3c: SRL(cpu, cpu->h); break; case 0x3d: SRL(cpu, cpu->l); break; case 0x3e: ASSERT(0); break; case 0x3f: SRL(cpu, cpu->a); break; case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: switch (inst & 7) { case 0: cpu->b; break; case 1: val = cpu->c; break; case 2: val = cpu->d; break; case 3: val = cpu->e; break; case 4: val = cpu->h; break; case 5: val = cpu->l; break; case 7: val = cpu->a; break; case 6: val = gb_mem_read(cpu->memory, cpu->hl); } BIT(cpu, val, (inst >> 3) & 7); break; case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: switch (inst & 7) { case 0: reg = &cpu->b; break; case 1: reg = &cpu->c; break; case 2: reg = &cpu->d; break; case 3: reg = &cpu->e; break; case 4: reg = &cpu->h; break; case 5: reg = &cpu->l; break; case 7: reg = &cpu->a; break; case 6: val = gb_mem_read(cpu->memory, cpu->hl); CLR_BIT(val, (inst >> 3) & 7); gb_mem_write(cpu->memory, cpu->hl, val); } if (!reg) break; CLR_BIT(val, (inst >> 3) & 7); *reg = val; break; case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: switch (inst & 7) { case 0: reg = &cpu->b; break; case 1: reg = &cpu->c; break; case 2: reg = &cpu->d; break; case 3: reg = &cpu->e; break; case 4: reg = &cpu->h; break; case 5: reg = &cpu->l; break; case 7: reg = &cpu->a; break; case 6: val = gb_mem_read(cpu->memory, cpu->hl); CLR_BIT(val, (inst >> 3) & 7); gb_mem_write(cpu->memory, cpu->hl, val); } if (!reg) break; SET_BIT(val, (inst >> 3) & 7); *reg = val; break; default: assert(0); } break; case 0xcc: /* CALL Z */ if (cpu->zf) { CALL(cpu); } else { cpu->pc += 2; } break; case 0xcd: /* CALL */ CALL(cpu); break; case 0xce: /* ADC A, d8 */ val = gb_mem_read(cpu->memory, cpu->pc++); ADC_8(cpu, cpu->a, val); break; case 0xcf: /* RST 08 */ RST(cpu, 0x08); break; case 0xd0: /* RET NC */ if (!cpu->cf) { RET(cpu); } break; case 0xd1: /* POP DE */ POP_16(cpu, cpu->de); break; case 0xd2: /* JP NC, a16 */ val_16 = gb_mem_read(cpu->memory, cpu->pc++); val_16 |= ((uint16_t) gb_mem_read(cpu->memory, cpu->pc++) << 8); if (!cpu->cf) { cpu->pc = val_16; } break; case 0xd3: /* UNDEF */ if (cpu->undef_d3) { /* Undo the incremented PC so the op is called with the PC at the D3 instruction */ cpu->metrics.cycles--; cpu->stall_cycles = 0; cpu->pc--; cpu->undef_d3(cpu); } break; case 0xd4: /* CALL NC */ if (!cpu->cf) { CALL(cpu); } else { cpu->pc += 2; } break; case 0xd5:/* PUSH DE */ PUSH_16(cpu, cpu->de); break; case 0xd6: /* SUB A,d8 */ val = gb_mem_read(cpu->memory, cpu->pc++); SUB_8(cpu, cpu->a, val); break; case 0xd7: /* RST 0x10 */ RST(cpu, 0x10); break; case 0xd8: /* RET C */ if (cpu->cf) { RET(cpu); } break; case 0xd9: /* RETI */ RET(cpu); gb_interrupt_ime_set(cpu->interrupt); break; case 0xda: /* JP C, a16 */ val_16 = gb_mem_read(cpu->memory, cpu->pc++); val_16 |= ((uint16_t) gb_mem_read(cpu->memory, cpu->pc++) << 8); if (cpu->cf) { cpu->pc = val_16; } break; case 0xdb: /* UNDEF */ break; case 0xdc: /* CALL C */ if (cpu->cf) { CALL(cpu); } else { cpu->pc += 2; } break; case 0xdd: /* UNDEF */ ASSERT(0); break; case 0xde: /* SBC A, d8 */ val = gb_mem_read(cpu->memory, cpu->pc++); SBC_8(cpu, cpu->a, val); break; case 0xdf: /* RST 0x18 */ RST(cpu, 0x18); break; case 0xe0: /* LDH (a8), A / LD ($FF00+a8),A */ val = gb_mem_read(cpu->memory, cpu->pc++); gb_mem_write(cpu->memory, 0xff00 + val, cpu->a); break; case 0xe1: /* POP HL */ POP_16(cpu, cpu->hl); break; case 0xe2: gb_mem_write(cpu->memory, 0xff00 + cpu->c, cpu->a); break; case 0xe3: /* UNDEF */ case 0xe4: /* UNDEF */ ASSERT(0); case 0xe5: /* PUSH HL */ PUSH_16(cpu, cpu->hl); break; case 0xe6: /* AND A, d8 */ val = gb_mem_read(cpu->memory, cpu->pc++); AND_8(cpu, cpu->a, val); break; case 0xe7: /* RST 0x20 */ RST(cpu, 0x20); break; case 0xe8: /* ADD SP, r8 */ val_16 = gb_mem_read(cpu->memory, cpu->pc++); if (val_16 & 0x80) { val_16 |= 0xff00; } cpu->cf = ADD_CARRY(cpu->sp, val_16, 8); cpu->hf = ADD_CARRY(cpu->sp, val_16, 4); cpu->zf = 0; cpu->nf = 0; cpu->sp += val_16; break; case 0xe9: /* JP (hl) */ cpu->pc = cpu->hl; break; case 0xea: /* LD (a16), A */ val_16 = gb_mem_read(cpu->memory, cpu->pc++); val_16 |= gb_mem_read(cpu->memory, cpu->pc++) << 8; gb_mem_write(cpu->memory, val_16, cpu->a); break; case 0xeb: /* UNDEF */ case 0xec: /* UNDEF */ case 0xed: /* UNDEF */ ASSERT(0); case 0xee: /* XOR d8 */ val = gb_mem_read(cpu->memory, cpu->pc++); XOR_8(cpu, cpu->a, val); break; case 0xef: /* RST 0x28 */ RST(cpu, 0x28); break; case 0xf0: /* LDH A,(a8) / LD A,($FF00+a8) */ val = gb_mem_read(cpu->memory, cpu->pc++); cpu->a = gb_mem_read(cpu->memory, 0xff00 + val); if (cpu->pc == 0x66) { break; } break; case 0xf1: /* POP AF */ val = gb_mem_read(cpu->memory, cpu->sp++); cpu->a = gb_mem_read(cpu->memory, cpu->sp++); cpu->zf = GET_BIT(val, CPU_F_BIT_POS_Z); cpu->nf = GET_BIT(val, CPU_F_BIT_POS_N); cpu->hf = GET_BIT(val, CPU_F_BIT_POS_H); cpu->cf = GET_BIT(val, CPU_F_BIT_POS_C); break; case 0xf2: /* LD A,(C) / LD A,(C+$FF00) */ cpu->a = gb_mem_read(cpu->memory, 0xFF00 + cpu->c); break; case 0xf3: /* DI */ gb_interrupt_ime_clear(cpu->interrupt); break; case 0xf4: /* UNDEF */ break; case 0xf5: /* PUSH AF */ val = cpu->zf << CPU_F_BIT_POS_Z; val |= cpu->nf << CPU_F_BIT_POS_N; val |= cpu->cf << CPU_F_BIT_POS_C; val |= cpu->hf << CPU_F_BIT_POS_H; gb_mem_write(cpu->memory, --cpu->sp, cpu->a); gb_mem_write(cpu->memory, --cpu->sp, val); break; case 0xf6: /* OR d8 */ val = gb_mem_read(cpu->memory, cpu->pc++); OR_8(cpu, cpu->a, val); break; case 0xf7: /* RST 0x30 */ RST(cpu, 0x30); break; case 0xf8: /* LD HL, SP+r8 */ val_16 = gb_mem_read(cpu->memory, cpu->pc++); if (val_16 & 0x80) { val_16 |= 0xff00; } cpu->cf = ADD_CARRY(cpu->sp, val_16, 8); cpu->hf = ADD_CARRY(cpu->sp, val_16, 4); cpu->zf = 0; cpu->nf = 0; cpu->hl = cpu->sp + val_16; break; case 0xf9: /* LD SP, HL */ cpu->sp = cpu->hl; break; case 0xfa: val_16 = gb_mem_read(cpu->memory, cpu->pc++); val_16 |= gb_mem_read(cpu->memory, cpu->pc++) << 8; cpu->a = gb_mem_read(cpu->memory, val_16); break; case 0xfb: /* EI */ gb_log("EI\n"); gb_interrupt_ime_set(cpu->interrupt); break; case 0xfc: /* UNDEF */ ASSERT(0); break; case 0xfd: /* UNDEF */ break; case 0xfe: /* CP d8 */ CP_8(cpu, cpu->a, gb_mem_read(cpu->memory, cpu->pc++)); break; case 0xff: /* RST 0x38 */ RST(cpu, 0x38); break; } cpu->metrics.cycles += cycles + 1; return cycles + 1; } void lr35902_interrupt(struct lr35902_state *cpu, enum gb_interrupt_kind kind) { uint16_t addr; gb_log("Interrupt! (%d)\n", kind); switch (kind) { case GB_INT_VBLANK: addr = 0x40; break; case GB_INT_LCD_STAT: addr = 0x48; break; case GB_INT_TIMER: addr = 0x50; break; case GB_INT_SERIAL: addr = 0x58; break; case GB_INT_JOYPAD: addr = 0x60; break; default: ASSERT(0); } PUSH_16(cpu, cpu->pc); cpu->pc = addr; }