Files
gb-emu/src/gbemu/cpu.c
Max Regan 1076d02638 interrupt: first-pass implementation of interrupts
Only manual and V-blank interrupts work, for now. This implements
enough to make the EI and DI parts of Blargg's Interrupt test pass.
2018-09-20 20:55:51 -07:00

1824 lines
37 KiB
C

/*
* Author: Max Regan
* Last Modified: 11-17-2015
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#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;
}