Files
gb-emu/src/cpu.c
Max Regan b6f9557d11 cpu: cleanup to use named registers
Since we have direct access to registers via name by "cpu->a" and the
like. Use that notation in a few more places since it is far more concise.

Signed-off-by: Max Regan <mgregan2@gmail.com>
2017-05-10 22:40:12 -07:00

1464 lines
32 KiB
C

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