/* * Author: Max Regan * Last Modified: 11-17-2015 */ #include #include #include "cpu.h" #include "common.h" #define WRITE_BIT(x, idx, bit) \ do {(x) &= (~(1 << (idx)) | ((bit) << (idx)));} while(0) #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) /*TODO: Timings are all totally boned */ /* Primary instructions */ static void nop(struct lr35902_state *cpu, uint8_t instr); static void ld(struct lr35902_state *cpu, uint8_t instr); static void ld_deref(struct lr35902_state *cpu, uint8_t instr); static void ld_into_deref(struct lr35902_state *cpu, uint8_t instr); static void ld_d8(struct lr35902_state *cpu, uint8_t instr); static void ld_d16(struct lr35902_state *cpu, uint8_t instr); static void ld_a16(struct lr35902_state *cpu, uint8_t instr); static void ld_c_offset(struct lr35902_state *cpu, uint8_t instr); static void ld_hl_d16(struct lr35902_state *cpu, uint8_t inst); static void inc(struct lr35902_state *cpu, uint8_t instr); static void inc_16(struct lr35902_state *cpu, uint8_t instr); static void dec(struct lr35902_state *cpu, uint8_t instr); static void dec_16(struct lr35902_state *cpu, uint8_t instr); static void rlca(struct lr35902_state *cpu, uint8_t instr); static void add(struct lr35902_state *cpu, uint8_t instr); static void rrca(struct lr35902_state *cpu, uint8_t instr); static void stop(struct lr35902_state *cpu, uint8_t instr); static void rla(struct lr35902_state *cpu, uint8_t instr); static void jr(struct lr35902_state *cpu, uint8_t instr); static void jr_cond(struct lr35902_state *cpu, uint8_t instr); static void rra(struct lr35902_state *cpu, uint8_t instr); static void daa(struct lr35902_state *cpu, uint8_t instr); static void cpl(struct lr35902_state *cpu, uint8_t instr); static void scf(struct lr35902_state *cpu, uint8_t instr); static void ccf(struct lr35902_state *cpu, uint8_t instr); static void halt(struct lr35902_state *cpu, uint8_t instr); static void adc(struct lr35902_state *cpu, uint8_t instr); static void sub(struct lr35902_state *cpu, uint8_t instr); static void sbc(struct lr35902_state *cpu, uint8_t instr); static void and(struct lr35902_state *cpu, uint8_t instr); static void xor(struct lr35902_state *cpu, uint8_t instr); static void or(struct lr35902_state *cpu, uint8_t instr); static void cp(struct lr35902_state *cpu, uint8_t instr); static void ret(struct lr35902_state *cpu, uint8_t instr); static void pop(struct lr35902_state *cpu, uint8_t instr); static void jp(struct lr35902_state *cpu, uint8_t instr); static void jp_a16(struct lr35902_state *cpu, uint8_t instr); static void jp_d8(struct lr35902_state *cpu, uint8_t instr); static void call(struct lr35902_state *cpu, uint8_t instr); static void push(struct lr35902_state *cpu, uint8_t instr); static void add_d8(struct lr35902_state *cpu, uint8_t instr); static void rst(struct lr35902_state *cpu, uint8_t instr); static void cb_prefix(struct lr35902_state *cpu, uint8_t instr); static void adc_d8(struct lr35902_state *cpu, uint8_t instr); static void undef(struct lr35902_state *cpu, uint8_t instr); static void sub_d8(struct lr35902_state *cpu, uint8_t instr); static void reti(struct lr35902_state *cpu, uint8_t instr); static void sbc_d8(struct lr35902_state *cpu, uint8_t instr); static void ldh(struct lr35902_state *cpu, uint8_t instr); static void and_d8(struct lr35902_state *cpu, uint8_t instr); static void xor_d8(struct lr35902_state *cpu, uint8_t instr); static void di(struct lr35902_state *cpu, uint8_t instr); static void or_d8(struct lr35902_state *cpu, uint8_t instr); static void ei(struct lr35902_state *cpu, uint8_t instr); static void cp_d8(struct lr35902_state *cpu, uint8_t instr); /* C-u M-x align-regexp \(,\) RET RET y */ lr35902_instr lr35902_instrs[] = { /*0x0?*/ nop, ld_d16, ld_into_deref, inc_16, inc, dec, ld_d8, rlca, ld, add, ld, dec_16, inc, dec, ld_d8, rrca, /*0x1?*/ stop, ld_d16, ld_into_deref, inc_16, inc, dec, ld_d8, rla, jr, add, ld_deref, dec_16, inc, dec, ld_d8, rra, /*0x2?*/ jr_cond, ld_d16, ld_deref, inc_16, inc, dec, ld_d8, daa, jr_cond, add, ld_hl_d16, dec_16, inc, dec, ld_d8, cpl, /*0x3?*/ jr_cond, ld_d16, ld_deref, inc_16, inc, dec, ld_d8, scf, jr_cond, add, ld, dec_16, inc, dec, ld_d8, ccf, /*0x4?*/ ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, /*0x5?*/ ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, /*0x6?*/ ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, ld, /*0x7?*/ ld, ld, ld, ld, ld, ld, halt, ld_into_deref, ld, ld, ld, ld, ld, ld, ld, ld, /*0x8?*/ add, add, add, add, add, add, add, add, adc, adc, adc, adc, adc, adc, adc, adc, /*0x9?*/ sub, sub, sub, sub, sub, sub, sub, sub, sbc, sbc, sbc, sbc, sbc, sbc, sbc, sbc, /*0xA?*/ and, and, and, and, and, and, and, and, xor, xor, xor, xor, xor, xor, xor, xor, /*0xB?*/ or, or, or, or, or, or, or, or, cp, cp, cp, cp, cp, cp, cp, cp, /*0xC?*/ ret, pop, jp_a16, jp_d8, call, push, add_d8, rst, ret, ret, jp_a16, cb_prefix, call, call, adc_d8, rst, /*0xD?*/ ret, pop, jp_a16, undef, call, push, sub_d8, rst, ret, reti, jp, undef, call, undef, sbc_d8, rst, /*0xE?*/ ldh, pop, ld_c_offset, undef, undef, push, and_d8, rst, add, jp, ld_a16, undef, undef, undef, xor_d8, rst, /*0xF?*/ ldh, pop, ld_c_offset, di, undef, push, or_d8, rst, ld, ld, ld_a16, ei, undef, undef, cp_d8, rst, }; /* CB-prefix functions*/ static void rlc(struct lr35902_state *cpu, uint8_t instr); static void rrc(struct lr35902_state *cpu, uint8_t instr); static void rl(struct lr35902_state *cpu, uint8_t instr); static void rr(struct lr35902_state *cpu, uint8_t instr); static void sla(struct lr35902_state *cpu, uint8_t instr); static void sra(struct lr35902_state *cpu, uint8_t instr); static void swap(struct lr35902_state *cpu, uint8_t instr); static void srl(struct lr35902_state *cpu, uint8_t instr); static void bit(struct lr35902_state *cpu, uint8_t instr); static void res(struct lr35902_state *cpu, uint8_t instr); static void set(struct lr35902_state *cpu, uint8_t instr); static lr35902_instr lr35902_cb_instrs[] = { /*0x0?*/ rlc, rrc, /*0x1?*/ rl, rr, /*0x2?*/ sla, sra, /*0x3?*/ swap, srl, /*0x4?*/ bit, bit, /*0x5?*/ bit, bit, /*0x6?*/ bit, bit, /*0x7?*/ bit, bit, /*0x8?*/ res, res, /*0x9?*/ res, res, /*0xA?*/ res, res, /*0xB?*/ res, res, /*0xC?*/ set, set, /*0xD?*/ set, set, /*0xE?*/ set, set, /*0xF?*/ set, set, }; 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(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(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; } static void _incr_pc(struct lr35902_state *cpu) { cpu->pc++; } /* * Runs any deferred events if it is their time to run */ static void _run_events(struct lr35902_state *cpu) { int i; for (i = 0; i < LR35902_MAX_EVENTS; i++) { if (cpu->events[i].cycles == 1) { cpu->events[i].run(cpu); } if (cpu->events[i].cycles > 0) { cpu->events[i].cycles--; } } } static void _schedule_event(struct lr35902_state *cpu, lr35902_event_fn fn, uint8_t cycles) { int i; for (i = 0; i < LR35902_MAX_EVENTS; i++) { if (cpu->events[i].cycles == 0) { cpu->events[i].cycles = cycles; cpu->events[i].run = fn; return; } } _run_events(cpu); cpu->halted=1; } static void _enable_interrupts(struct lr35902_state *cpu) { cpu->int_state = LR35902_INT_ON; } static void _disable_interrupts(struct lr35902_state *cpu) { cpu->int_state = LR35902_INT_OFF; } static void _push_stack_8(struct lr35902_state *cpu, uint8_t val) { cpu->mem_write(cpu, cpu->sp, val); cpu->sp--; } static void _push_stack_16(struct lr35902_state *cpu, uint16_t val) { _push_stack_8(cpu, val >> 8); _push_stack_8(cpu, val & 0xFF); } static uint8_t _pop_stack_8(struct lr35902_state *cpu) { return cpu->mem_read(cpu, cpu->sp++); } static uint16_t _pop_stack_16(struct lr35902_state *cpu) { uint16_t val; val = _pop_stack_8(cpu); val |= _pop_stack_8(cpu) << 8; return 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; } void lr35902_cycle(struct lr35902_state *cpu) { uint8_t instr = cpu->mem_read(cpu, cpu->pc); cpu->metrics.cycles++; if(cpu->stall_cycles > 0){ cpu->stall_cycles--; return; } lr35902_instrs[instr](cpu, instr); cpu->metrics.retired_instrs++; cpu->pc++; _run_events(cpu); return; } static uint8_t _get_reg_8(struct lr35902_state *cpu, uint8_t reg){ if (reg == LR35902_REG_HL_DEREF){ return cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_HL)); } else { return cpu->regs_8[cpu_reg8_to_idx[reg]]; } } static void _set_reg_8(struct lr35902_state *cpu, uint8_t reg, uint8_t val){ ASSERT(reg < NUM_LR35902_REGS_8 && reg >= 0); if (reg == LR35902_REG_HL_DEREF){ cpu->mem_write(cpu, lr35902_get_reg_16(cpu, LR35902_REG_HL), val); } else { cpu->regs_8[cpu_reg8_to_idx[reg]] = val; } } /************************/ /* Primary instructions */ /************************/ static void nop(struct lr35902_state *cpu, uint8_t instr) { return; } static void ld(struct lr35902_state *cpu, uint8_t instr) { uint8_t val; uint8_t src_reg, dst_reg; if (!(instr > 0x40 && instr <= 0x7F)) { cpu->halted = 1; return; } dst_reg = (instr >> 3) & 7; src_reg = instr & 7; val = _get_reg_8(cpu, src_reg); _set_reg_8(cpu, dst_reg, val); } static void ld_deref(struct lr35902_state *cpu, uint8_t instr) { int incr = 0; uint8_t val; switch(instr) { /** Copy to Registers **/ case 0x0A: cpu->a = cpu->mem_read(cpu, cpu->bc); break; case 0x1A: cpu->a = cpu->mem_read(cpu, cpu->de); break; case 0x2A: incr = 1; /* Intentional fall-through */ case 0x3A: val = cpu->mem_read(cpu, cpu->hl); cpu->a = val; if (incr) { cpu->hl++; } else { cpu->hl--; } lr35902_set_reg_16(cpu, LR35902_REG_HL, cpu->hl); break; /** Copy to memory **/ case 0x22: incr = 1; /* Intentional fall-through */ case 0x32: cpu->mem_write(cpu, cpu->hl, cpu->a); if (incr) { cpu->hl++; } else { cpu->hl--; } break; case 0x12: cpu->mem_write(cpu, cpu->de, cpu->a); break; case 0x02: cpu->mem_write(cpu, cpu->bc, cpu->a); break; default: cpu->halted = 1; } } static void ld_into_deref(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg; uint16_t addr; switch (instr) { case 0x02: reg = LR35902_REG_BC; break; case 0x12: reg = LR35902_REG_DE; break; case 0x77: reg = LR35902_REG_HL; break; default: ASSERT(0); return; } addr = lr35902_get_reg_16(cpu, reg); cpu->mem_write(cpu, addr, cpu->a); } static void ld_d8(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = (instr >> 3) & 0x7; ++cpu->pc; _set_reg_8(cpu, reg, cpu->mem_read(cpu, cpu->pc)); } static void ld_d16(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg; uint16_t val; switch(instr) { case 0x01: reg = LR35902_REG_BC; break; case 0x11: reg = LR35902_REG_DE; break; case 0x21: reg = LR35902_REG_HL; break; case 0x31: reg = LR35902_REG_SP; break; default: cpu->halted=1; return; } val = cpu->mem_read(cpu, ++cpu->pc); val |= cpu->mem_read(cpu, ++cpu->pc) << 8; lr35902_set_reg_16(cpu, reg, val); } static void ld_a16(struct lr35902_state *cpu, uint8_t instr) { uint16_t a = 0; _incr_pc(cpu); a = cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC)); _incr_pc(cpu); a |= cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC)) << 8; if(instr == 0xEA) { /* Store */ uint16_t val = lr35902_get_reg_8(cpu, LR35902_REG_A); cpu->mem_write(cpu, a, val); } else { /* Load */ lr35902_set_reg_8(cpu, LR35902_REG_A, cpu->mem_read(cpu, a)); } } static void ld_c_offset(struct lr35902_state *cpu, uint8_t instr) { uint16_t addr = 0; addr = cpu->c; addr |= 0xff00; switch (instr) { case 0xf2: //LD A, ($FF00 + C) cpu->a = cpu->mem_read(cpu, addr); break; case 0xe2: //LD ($FF00 + C), A cpu->mem_write(cpu, addr, cpu->a); break; default: ASSERT(0); } } static void ld_hl_d16(struct lr35902_state *cpu, uint8_t inst) { cpu->a = cpu->mem_read(cpu, cpu->hl++); } static void inc_16(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg; uint16_t val; switch (instr) { case 0x03: reg = LR35902_REG_BC; break; case 0x13: reg = LR35902_REG_DE; break; case 0x23: reg = LR35902_REG_HL; break; case 0x33: reg = LR35902_REG_SP; break; default: ASSERT(0); return; } val = lr35902_get_reg_16(cpu, reg); val++; lr35902_set_reg_16(cpu, reg, val); } static void inc(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = (instr >> 3) & 0x7; uint8_t val = _get_reg_8(cpu, reg); val++; _set_reg_8(cpu, reg, val); } static void dec(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = (instr >> 3) & 0x7; uint8_t val = _get_reg_8(cpu, reg); val--; _set_reg_8(cpu, reg, val); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val == 0); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_N, 1); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_H, (val == 0xFF)); } static void dec_16(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = (instr & 0xF0) >> 8; uint16_t val; switch (reg) { case 0: reg = LR35902_REG_BC; break; case 1: reg = LR35902_REG_DE; break; case 2: reg = LR35902_REG_HL; break; case 3: reg = LR35902_REG_SP; break; default: printf("reg: %d\n", reg); ASSERT(0); } val = lr35902_get_reg_16(cpu, reg); val--; lr35902_set_reg_16(cpu, reg, val); } static void rlca(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = LR35902_REG_A; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val << 1); new_val |= GET_BIT(val, 7); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, (new_val == 0)); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 7)); } static void rrca(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = LR35902_REG_A; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val >> 1); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, (new_val == 0)); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 7)); } static void rla(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = LR35902_REG_A; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val << 1); new_val |= GET_BIT(val, 7); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, (new_val == 0)); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 7)); } static void rra(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = LR35902_REG_A; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val >> 1); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, (new_val == 0)); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 7)); } static void add(struct lr35902_state *cpu, uint8_t instr) { uint8_t val_a = _get_reg_8(cpu, LR35902_REG_A); uint8_t val = _get_reg_8(cpu, instr & 7); uint8_t res = val + val_a; _set_reg_8(cpu, LR35902_REG_A, (uint8_t) res); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, res == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_H, GET_BIT(val_a, 8)); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(res, 4)); } static void add_d8(struct lr35902_state *cpu, uint8_t instr) { cpu->halted=1; } static void adc(struct lr35902_state *cpu, uint8_t instr) { uint8_t val_a = _get_reg_8(cpu, LR35902_REG_A); uint8_t val = _get_reg_8(cpu, instr & 7); uint16_t res = val + val_a + cpu->c; _set_reg_8(cpu, LR35902_REG_A, (uint8_t) res); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, res == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_H, GET_BIT(val_a, 8)); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(res, 4)); } static void adc_d8(struct lr35902_state *cpu, uint8_t instr) { cpu->halted=1; } static void sub(struct lr35902_state *cpu, uint8_t instr) { uint8_t val_a = _get_reg_8(cpu, LR35902_REG_A); uint8_t val = _get_reg_8(cpu, instr & 7); val_a -= val; _set_reg_8(cpu, LR35902_REG_A, val_a); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val_a == 0); SET_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); //TODO: No borrow from bit 4 CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); //TODO: No borrow } static void sub_d8(struct lr35902_state *cpu, uint8_t instr) { cpu->halted=1; } static void sbc(struct lr35902_state *cpu, uint8_t instr) { uint8_t val_a = _get_reg_8(cpu, LR35902_REG_A); uint8_t val = _get_reg_8(cpu, instr & 7); val_a -= val + cpu->c; _set_reg_8(cpu, LR35902_REG_A, val_a); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val_a == 0); SET_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); //TODO: No borrow from bit 4 CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); //TODO: No borrow } static void sbc_d8(struct lr35902_state *cpu, uint8_t instr) { cpu->halted=1; } static void and(struct lr35902_state *cpu, uint8_t instr) { uint8_t val_a = _get_reg_8(cpu, LR35902_REG_A); uint8_t val = _get_reg_8(cpu, instr & 7); val_a &= val; _set_reg_8(cpu, LR35902_REG_A, val_a); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); SET_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void and_d8(struct lr35902_state *cpu, uint8_t instr) { uint8_t val; _incr_pc(cpu); val = cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC)); val &= lr35902_get_reg_8(cpu, LR35902_REG_A); _set_reg_8(cpu, LR35902_REG_A, val); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); SET_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void xor(struct lr35902_state *cpu, uint8_t instr) { uint8_t val_a = _get_reg_8(cpu, LR35902_REG_A); uint8_t val = _get_reg_8(cpu, instr & 7); val_a ^= val; _set_reg_8(cpu, LR35902_REG_A, val_a); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val_a == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void xor_d8(struct lr35902_state *cpu, uint8_t instr) { uint8_t val; _incr_pc(cpu); val = cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC)); val ^= lr35902_get_reg_8(cpu, LR35902_REG_A); _set_reg_8(cpu, LR35902_REG_A, val); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void or(struct lr35902_state *cpu, uint8_t instr) { uint8_t val_a = _get_reg_8(cpu, LR35902_REG_A); uint8_t val = _get_reg_8(cpu, instr & 7); val_a |= val; _set_reg_8(cpu, LR35902_REG_A, val_a); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val_a == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void or_d8(struct lr35902_state *cpu, uint8_t instr) { uint8_t val; _incr_pc(cpu); val = cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC)); val |= lr35902_get_reg_8(cpu, LR35902_REG_A); _set_reg_8(cpu, LR35902_REG_A, val); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void cp(struct lr35902_state *cpu, uint8_t instr) { uint8_t val_a = _get_reg_8(cpu, LR35902_REG_A); uint8_t val = _get_reg_8(cpu, instr & 7); val_a -= val; /* Just test, ignore result */ WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val_a == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void cp_d8(struct lr35902_state *cpu, uint8_t instr) { uint8_t val_a = _get_reg_8(cpu, LR35902_REG_A); _incr_pc(cpu); uint16_t pc = lr35902_get_reg_16(cpu, LR35902_REG_PC); uint8_t val = cpu->mem_read(cpu, pc); val_a -= val; /* Just test, ignore result */ WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, val_a == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void stop(struct lr35902_state *cpu, uint8_t instr) { cpu->halted=1; } static void jr(struct lr35902_state *cpu, uint8_t instr) { uint16_t pc = lr35902_get_reg_16(cpu, LR35902_REG_PC); uint8_t off = cpu->mem_read(cpu, pc + 1); uint16_t off16; if (GET_BIT(off, 7)) { off16 = (uint16_t) 0xFF00 | off; } else { off16 = off; } pc += off16; lr35902_set_reg_16(cpu, LR35902_REG_PC, pc); _incr_pc(cpu); } static void jr_cond(struct lr35902_state *cpu, uint8_t instr) { uint8_t flag = (instr >> 3) & 3; uint16_t pc = lr35902_get_reg_16(cpu, LR35902_REG_PC); uint16_t offset = cpu->mem_read(cpu, pc + 1); if (GET_BIT(offset, 7)) { offset |= 0xFF00; /* Sign extend */ } switch(flag) { case 0: flag = GET_BIT(cpu->f, LR35902_FLAG_BIT_Z) == 0; break; case 1: flag = GET_BIT(cpu->f, LR35902_FLAG_BIT_Z) == 1; break; case 2: flag = GET_BIT(cpu->f, LR35902_FLAG_BIT_C) == 0; break; case 3: flag = GET_BIT(cpu->f, LR35902_FLAG_BIT_C) == 1; break; default: cpu->halted=1; } if(flag) { pc += offset; lr35902_set_reg_16(cpu, LR35902_REG_PC, pc); } _incr_pc(cpu); } static void daa(struct lr35902_state *cpu, uint8_t instr) { cpu->halted=1; } static void cpl(struct lr35902_state *cpu, uint8_t instr) { uint8_t val = _get_reg_8(cpu, LR35902_REG_A); val = ~val; _set_reg_8(cpu, LR35902_REG_A, val); SET_BIT(cpu->f, LR35902_FLAG_BIT_N); SET_BIT(cpu->f, LR35902_FLAG_BIT_H); } static void scf(struct lr35902_state *cpu, uint8_t instr) { SET_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void ccf(struct lr35902_state *cpu, uint8_t instr) { cpu->f ^= 1 << LR35902_FLAG_BIT_C; } static void halt(struct lr35902_state *cpu, uint8_t instr) { cpu->halted = 1; } static void ret(struct lr35902_state *cpu, uint8_t instr) { uint16_t jmp_addr = _pop_stack_16(cpu); lr35902_set_reg_16(cpu, LR35902_REG_PC, jmp_addr - 1); } static void pop(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg; uint16_t val; switch(instr) { case 0xC1: reg = LR35902_REG_BC; break; case 0xD1: reg = LR35902_REG_DE; break; case 0xE1: reg = LR35902_REG_HL; break; case 0xF1: reg = LR35902_REG_AF; break; default: ASSERT(0); return; } val = _pop_stack_16(cpu); lr35902_set_reg_16(cpu, reg, val); } static void jp(struct lr35902_state *cpu, uint8_t instr) { cpu->halted = 1; } static void jp_d8(struct lr35902_state *cpu, uint8_t instr) { uint16_t pc = lr35902_get_reg_16(cpu, LR35902_REG_PC); uint8_t jp_low = cpu->mem_read(cpu, pc + 1); uint8_t jp_hi = cpu->mem_read(cpu, pc + 2); uint16_t jp_addr = (jp_hi << 8) | jp_low; lr35902_set_reg_16(cpu, LR35902_REG_PC, jp_addr - 1); //TODO: This is a hack } static void jp_a16(struct lr35902_state *cpu, uint8_t instr) { uint16_t addr; uint8_t cond; switch (instr) { case 0xC2: cond = !GET_BIT(cpu->f, LR35902_FLAG_BIT_Z); break; /* JP NZ */ case 0xD2: cond = !GET_BIT(cpu->f, LR35902_FLAG_BIT_C); break; /* JP NC */ case 0xCA: cond = GET_BIT(cpu->f, LR35902_FLAG_BIT_Z); break; /* JP Z */ case 0xDA: cond = GET_BIT(cpu->f, LR35902_FLAG_BIT_C); break; /* JP C */ case 0xC3: cond = 1; break; /* JP */ default: ASSERT(0); return; } addr = cpu->mem_read(cpu, LR35902_REG_PC); _incr_pc(cpu); addr |= cpu->mem_read(cpu, LR35902_REG_PC) << 8; _incr_pc(cpu); if (cond) { lr35902_set_reg_16(cpu, LR35902_REG_PC, addr - 1); //TODO: This is a hack } } static void call(struct lr35902_state *cpu, uint8_t instr) { uint16_t jmp_addr; _push_stack_16(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC) + 3); _incr_pc(cpu); jmp_addr = cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC)); _incr_pc(cpu); jmp_addr |= (cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC))) << 8; lr35902_set_reg_16(cpu, LR35902_REG_PC, jmp_addr - 1); } static void push(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = (instr >> 5) & 7; uint16_t val; switch(instr) { case 0xF5: reg = LR35902_REG_AF; break; case 0xC5: reg = LR35902_REG_BC; break; case 0xD5: reg = LR35902_REG_DE; break; case 0xE5: reg = LR35902_REG_HL; break; default: ASSERT(0); } val = lr35902_get_reg_16(cpu, reg); _push_stack_16(cpu, val); } static void rst(struct lr35902_state *cpu, uint8_t instr) { cpu->halted=1; } static void cb_prefix(struct lr35902_state *cpu, uint8_t instr) { uint8_t cb_instr; _incr_pc(cpu); cb_instr = cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC)); lr35902_cb_instrs[cb_instr >> 3](cpu, cb_instr); } static void undef(struct lr35902_state *cpu, uint8_t instr) { cpu->halted=1; } static void reti(struct lr35902_state *cpu, uint8_t instr) { cpu->halted=1; } static void ldh(struct lr35902_state *cpu, uint8_t instr) { //TODO: This is the blocking one (0xE0) uint16_t addr = 0; _incr_pc(cpu); addr = cpu->mem_read(cpu, lr35902_get_reg_16(cpu, LR35902_REG_PC)); addr += 0xFF00; if(instr == 0xE0) { /* Store */ uint16_t val_a = lr35902_get_reg_8(cpu, LR35902_REG_A); uint8_t val = (uint8_t) val_a & 0xFF; cpu->mem_write(cpu, addr, val); } else if (instr == 0xF0) { /* Load */ uint8_t val = cpu->mem_read(cpu, addr); uint16_t val_a = val; lr35902_set_reg_8(cpu, LR35902_REG_A, val_a); } else { cpu->halted = 1; } } static void di(struct lr35902_state *cpu, uint8_t instr) { _schedule_event(cpu, _disable_interrupts, 2); } static void ei(struct lr35902_state *cpu, uint8_t instr) { _schedule_event(cpu, _enable_interrupts, 2); } /**************************/ /* CB-prefix instructions */ /**************************/ static void rlc(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val << 1); new_val |= GET_BIT(val, 7); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, new_val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void rrc(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val >> 1); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, new_val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 0)); } static void rl(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val << 1); new_val |= GET_BIT(val, 7); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, new_val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 7)); } static void rr(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val >> 1); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, new_val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 0)); } static void sla(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val << 1); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, new_val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 7)); } static void sra(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val >> 1); WRITE_BIT(new_val, 7, GET_BIT(val, 7)); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, new_val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 0)); } static void swap(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val >> 4) | (val << 4); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, new_val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); CLR_BIT(cpu->f, LR35902_FLAG_BIT_C); } static void srl(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = 0; new_val = (val >> 1); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, new_val == 0); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); CLR_BIT(cpu->f, LR35902_FLAG_BIT_H); WRITE_BIT(cpu->f, LR35902_FLAG_BIT_C, GET_BIT(val, 0)); } static void bit(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t bit = (instr >> 3) & 7; uint8_t val = _get_reg_8(cpu, reg); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; WRITE_BIT(cpu->f, LR35902_FLAG_BIT_Z, !GET_BIT(val, bit)); CLR_BIT(cpu->f, LR35902_FLAG_BIT_N); SET_BIT(cpu->f, LR35902_FLAG_BIT_H); } static void res(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t bit = (instr >> 3) & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = val; CLR_BIT(new_val, bit); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; } static void set(struct lr35902_state *cpu, uint8_t instr) { uint8_t reg = instr & 7; uint8_t bit = (instr >> 3) & 7; uint8_t val = _get_reg_8(cpu, reg); uint8_t new_val = val; SET_BIT(new_val, bit); _set_reg_8(cpu, reg, new_val); cpu->stall_cycles = (reg == LR35902_REG_HL_DEREF) ? 4 : 2; }