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>
1464 lines
32 KiB
C
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;
|
|
}
|