/* * Author: Max Regan * Last Modified: 11-17-2015 */ #include #include #include #include "gbemu/cpu.h" #include "common/common.h" #define SET_BIT(x, idx) do {(x) |= (1 << (idx));} while (0) #define CLR_BIT(x, idx) do {(x) &= ~(1 << (idx));} while (0) #define GET_BIT(x, bit) (((x) >> (bit)) & 1) #define WRITE_BIT(x, idx, bit) \ do {(x) &= (~(1 << (idx)) | ((bit) << (idx)));} while(0) #define CALC_H_ADD(a, b) ((((a) & 0xf) + ((b) & 0xf)) > 0xf) #define CALC_H_SUB(a, b) (((a) & 0xf) < ((b) & 0xf)) #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 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, lr35902_mem_read_fn mem_read, lr35902_mem_write_fn mem_write) { int i; cpu->mem_read = mem_read; cpu->mem_write = mem_write; 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) = (cpu)->mem_read((cpu), (cpu)->pc++); \ } while (0) #define LD_D16(cpu, reg) \ do { \ (reg) = (cpu)->mem_read((cpu), (cpu)->pc++); \ (reg) |= (uint16_t) (cpu)->mem_read((cpu), (cpu)->pc++) << 8; \ } while (0) #define ADD_8(cpu, dst, src) \ do { \ (cpu)->nf = 0; \ (cpu)->hf = CALC_H_ADD((src), (dst)); \ (cpu)->cf = CALC_C_ADD_8((src), (dst)); \ (dst) += (src); \ (cpu)->zf = (dst) == 0; \ } while (0) #define ADD_16(cpu, dst, src) \ do { \ (cpu)->nf = 0; \ (cpu)->hf = CALC_H_ADD((dst), (src)); \ (cpu)->cf = CALC_C_ADD_16((dst), (src)); \ (dst) += (src); \ } while (0) \ #define ADC_8(cpu, dst, src) \ do { \ /* FIXME flag generation */ \ int tmp; \ tmp = src + dst + cpu->cf; \ cpu->nf = 0; \ cpu->hf = CALC_H_ADD((src), (dst)); \ (dst) = tmp; \ cpu->zf = (dst) == 0; \ } while (0) #define SUB_8(cpu, dst, src) \ do { \ int tmp; \ tmp = dst - src; \ cpu->nf = 1; \ cpu->hf = CALC_H_SUB(src, dst); \ dst = tmp; \ cpu->zf = (dst) == 0; \ } while (0) #define SBC_8(cpu, dst, src) \ do { \ /* FIXME flag generation */ \ int tmp; \ tmp = (dst) - (src) - 1; \ (cpu)->nf = 1; \ (cpu)->hf = CALC_H_ADD(src, dst); \ (dst) = (tmp); \ cpu->zf = (dst) == 0; \ } while (0) #define AND_8(cpu, dst, src) \ do { \ (cpu)->nf = 0; \ (cpu)->hf = 1; \ (cpu)->cf = 0; \ (dst) &= (src); \ (cpu)->zf = ((dst) == 0); \ } while (0) #define XOR_8(cpu, dst, src) \ do { \ (cpu)->nf = 0; \ (cpu)->hf = 0; \ (cpu)->cf = 0; \ (dst) ^= (src); \ (cpu)->zf = ((dst) == 0); \ } while (0) #define OR_8(cpu, dst, src) \ do { \ (cpu)->nf = 0; \ (cpu)->hf = 0; \ (cpu)->cf = 0; \ (dst) |= (src); \ (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 = cpu->mem_read(cpu, cpu->pc++); \ /* sign-extend */ \ val_16 |= GET_BIT(val_16, 7) ? 0xff00 : 0; \ cpu->pc += val_16; \ } while (0) /* TODO: In general, check that we pop/push things correctly */ #define POP_16(cpu, dst) \ do { \ (dst) = (cpu)->mem_read((cpu), (cpu)->sp++); \ (dst) |= (uint16_t) (cpu)->mem_read((cpu), (cpu)->sp++) << 8; \ } while (0) #define PUSH_16(cpu, src) \ do { \ (cpu)->mem_write(cpu, --cpu->sp, src); \ (cpu)->mem_write(cpu, --cpu->sp, src >> 8); \ } while (0) #define CALL(cpu) \ do { \ uint16_t pc_base; \ cpu->mem_write(cpu, --cpu->sp, cpu->pc); \ cpu->mem_write(cpu, --cpu->sp, cpu->pc >> 8); \ pc_base = cpu->mem_read(cpu, cpu->pc++); \ pc_base |= (uint16_t) cpu->mem_read(cpu, cpu->pc) << 8; \ cpu->pc = pc_base; \ } while (0) #define RET(cpu) \ do { \ (cpu)->pc = 0; \ (cpu)->pc |= (uint16_t) (cpu)->mem_read((cpu), (cpu)->sp++) << 8; \ (cpu)->pc |= (cpu)->mem_read((cpu), (cpu)->sp++); \ (cpu)->pc += 2; \ } while (0) #define RST(cpu, n) \ do { \ (cpu)->mem_write((cpu), (cpu)->sp++, (cpu)->pc >> 8); \ (cpu)->mem_write((cpu), (cpu)->sp++, (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; \ } while (0) void lr35902_cycle(struct lr35902_state *cpu) { uint8_t inst; uint8_t val; uint16_t val_16; uint8_t *reg = NULL; cpu->metrics.cycles++; if (cpu->stall_cycles > 0) { cpu->stall_cycles--; if (cpu->stall_cycles == 0) { cpu->metrics.retired_instrs++; } return; } inst = cpu->mem_read(cpu, cpu->pc++); cpu->stall_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 */ cpu->mem_write(cpu, 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 */ cpu->sp = cpu->mem_read(cpu, cpu->pc++); cpu->sp |= cpu->mem_read(cpu, cpu->pc++) << 8; break; case 0x09: /* ADD HL, BC */ ADD_16(cpu, cpu->hl, cpu->bc); break; case 0x0a: /* LD A, (BC) */ cpu->a = cpu->mem_read(cpu, 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 */ cpu->cf = GET_BIT(cpu->a, 0); cpu->nf = 0; cpu->zf = 0; cpu->hf = 0; cpu->a >>= 1; WRITE_BIT(cpu->a, 7, cpu->cf); break; case 0x10: /* STOP */ //TODO: //cpu->stopped = true; break; case 0x11: /* LD DE, d16 */ LD_D16(cpu, cpu->de); break; case 0x12: /* LD (DE), A */ cpu->mem_write(cpu, 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 = cpu->mem_read(cpu, cpu->de); break; case 0x1b: /* DEC BC */ cpu->bc--; 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 */ cpu->a = cpu->mem_read(cpu, cpu->hl++); 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 */ /* TODO: DAA */ 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 = cpu->mem_read(cpu, cpu->hl); 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 */ cpu->mem_write(cpu, cpu->hl--, cpu->a); break; case 0x33: /* INC SP */ cpu->sp++; break; case 0x34: /* INC (HL) */ val = cpu->mem_read(cpu, cpu->hl); cpu->nf = 0; cpu->hf = CALC_H_ADD(val, 1); val++; cpu->mem_write(cpu, cpu->hl, val); cpu->zf = (val == 0); break; case 0x35: /* DEC (HL) */ val = cpu->mem_read(cpu, cpu->hl); cpu->hf = CALC_H_ADD(val, 1); cpu->zf = (val == 0); cpu->nf = 1; val--; cpu->mem_write(cpu, cpu->hl, val); break; case 0x36: /* LD (HL), d8 */ val = cpu->mem_read(cpu, cpu->pc++); cpu->mem_write(cpu, 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 = cpu->mem_read(cpu, cpu->hl); 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->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 = cpu->mem_read(cpu, 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 = cpu->mem_read(cpu, 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 = cpu->mem_read(cpu, 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->h; break; case 0x5e: /* LD E,(HL) */ cpu->e = cpu->mem_read(cpu, 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 = cpu->mem_read(cpu, 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 = cpu->mem_read(cpu, cpu->hl); break; case 0x6f: /* LD L,A */ cpu->l = cpu->a; break; case 0x70: /* LD (HL),B */ cpu->mem_write(cpu, cpu->hl, cpu->b); break; case 0x71: /* LD (HL),C */ cpu->mem_write(cpu, cpu->hl, cpu->c); break; case 0x72: /* LD (HL),D */ cpu->mem_write(cpu, cpu->hl, cpu->d); break; case 0x73: /* LD (HL),E */ cpu->mem_write(cpu, cpu->hl, cpu->e); break; case 0x74: /* LD (HL),H */ cpu->mem_write(cpu, cpu->hl, cpu->h); break; case 0x75: /* LD (HL),L */ cpu->mem_write(cpu, cpu->hl, cpu->l); break; case 0x76: /* HALT */ cpu->halted = 1; break; case 0x77: /* LD (HL),A */ cpu->mem_write(cpu, 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 = cpu->mem_read(cpu, 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,B */ ADD_8(cpu, cpu->a, cpu->l); break; case 0x86: /* ADD A,(HL) */ ADD_8(cpu, cpu->a, cpu->mem_read(cpu, 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->a); 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, cpu->mem_read(cpu, 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, cpu->mem_read(cpu, 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, cpu->mem_read(cpu, 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, cpu->mem_read(cpu, 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, cpu->mem_read(cpu, 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, cpu->mem_read(cpu, 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, cpu->mem_read(cpu, 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: case 0xc3: /* JP a16 */ val_16 = cpu->mem_read(cpu, cpu->pc++); val_16 |= ((uint16_t) cpu->mem_read(cpu, 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: 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: case 0xcb: inst = cpu->mem_read(cpu, cpu->pc++); cpu->stall_cycles = cb_extra_cycles[inst]; switch (inst) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: 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: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: 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 = cpu->mem_read(cpu, 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 = cpu->mem_read(cpu, cpu->hl); CLR_BIT(val, (inst >> 3) & 7); cpu->mem_write(cpu, 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 = cpu->mem_read(cpu, cpu->hl); CLR_BIT(val, (inst >> 3) & 7); cpu->mem_write(cpu, 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: 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: case 0xd3: /* UNDEF */ break; case 0xd4: /* CALL NC */ if (!cpu->nf) { CALL(cpu); } else { cpu->pc += 2; } break; case 0xd5:/* PUSH DE */ PUSH_16(cpu, cpu->de); break; case 0xd6: case 0xd7: /* RST 0x10 */ RST(cpu, 0x10); break; case 0xd8: /* RET C */ if (cpu->cf) { RET(cpu); } break; case 0xd9: /* RETI */ RET(cpu); cpu->int_state = LR35902_INT_ON; break; case 0xda: case 0xdb: /* UNDEF */ break; case 0xdc: /* CALL C */ if (cpu->cf) { CALL(cpu); } else { cpu->pc += 2; } break; case 0xdd: /* UNDEF */ break; case 0xde: case 0xdf: /* RST 0x18 */ RST(cpu, 0x18); break; case 0xe0: /* LDH (a8), A / LD ($FF00+a8),A */ val = cpu->mem_read(cpu, cpu->pc++); cpu->mem_write(cpu, 0xff00 + val, cpu->a); break; case 0xe1: /* POP HL */ POP_16(cpu, cpu->hl); break; case 0xe2: case 0xe3: /* UNDEF */ break; case 0xe4: /* UNDEF */ break; case 0xe5: /* PUSH HL */ PUSH_16(cpu, cpu->hl); break; case 0xe6: case 0xe7: /* RST 0x20 */ RST(cpu, 0x20); break; case 0xe8: case 0xe9: case 0xea: /* LD (a16), A */ val_16 = cpu->mem_read(cpu, cpu->pc++); val_16 |= cpu->mem_read(cpu, cpu->pc++) << 8; cpu->mem_write(cpu, val_16, cpu->a); break; case 0xeb: /* UNDEF */ break; case 0xec: /* UNDEF */ break; case 0xed: /* UNDEF */ break; case 0xee: case 0xef: /* RST 0x28 */ RST(cpu, 0x28); break; case 0xf0: /* LDH A,(a8) / LD A,($FF00+a8) */ val = cpu->mem_read(cpu, cpu->pc++); cpu->a = cpu->mem_read(cpu, 0xff00 + val); break; case 0xf1: /* POP AF */ cpu->a = cpu->mem_read(cpu, cpu->sp++); val = cpu->mem_read(cpu, 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: case 0xf3: case 0xf4: /* UNDEF */ break; case 0xf5: /* PUSH AF */ PUSH_16(cpu, cpu->af); break; case 0xf6: case 0xf7: /* RST 0x30 */ RST(cpu, 0x30); break; case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: /* UNDEF */ break; case 0xfd: /* UNDEF */ break; case 0xfe: /* CP d8 */ CP_8(cpu, cpu->a, cpu->mem_read(cpu, cpu->pc++)); break; case 0xff: /* RST 0x38 */ RST(cpu, 0x38); break; } }