mirror of https://github.com/mlaux/gb6.git
fix a bunch of instructions, passes most blargg tests now
This commit is contained in:
parent
b2a6890524
commit
ead7a3e17c
91
src/cpu.c
91
src/cpu.c
|
@ -73,13 +73,14 @@ static inline void write8(struct cpu *cpu, u16 address, u8 data)
|
|||
|
||||
static inline void write16(struct cpu *cpu, u16 address, u16 data)
|
||||
{
|
||||
dmg_write(cpu->dmg, address, data);
|
||||
dmg_write(cpu->dmg, address, data & 0xff);
|
||||
dmg_write(cpu->dmg, address + 1, data >> 8);
|
||||
}
|
||||
|
||||
static void inc_with_carry(struct cpu *regs, u8 *reg)
|
||||
{
|
||||
clear_flag(regs, FLAG_SIGN);
|
||||
if(*reg == 0xff || *reg == 0x0f)
|
||||
if((*reg & 0xf) == 0xf)
|
||||
set_flag(regs, FLAG_HALF_CARRY);
|
||||
else clear_flag(regs, FLAG_HALF_CARRY);
|
||||
(*reg)++;
|
||||
|
@ -91,7 +92,7 @@ static void inc_with_carry(struct cpu *regs, u8 *reg)
|
|||
static void dec_with_carry(struct cpu *regs, u8 *reg)
|
||||
{
|
||||
set_flag(regs, FLAG_SIGN);
|
||||
if(*reg == 0x00 || *reg == 0x10)
|
||||
if((*reg & 0xf) == 0)
|
||||
set_flag(regs, FLAG_HALF_CARRY);
|
||||
else clear_flag(regs, FLAG_HALF_CARRY);
|
||||
(*reg)--;
|
||||
|
@ -103,11 +104,20 @@ static void dec_with_carry(struct cpu *regs, u8 *reg)
|
|||
static u8 rotate_left(struct cpu *regs, u8 reg)
|
||||
{
|
||||
int old_carry = flag_isset(regs, FLAG_CARRY);
|
||||
// copy old leftmost bit to carry flag, clear Z, N, H
|
||||
regs->f = (reg & 0x80) >> 3;
|
||||
// rotate
|
||||
int result = reg << 1 | old_carry;
|
||||
if (!result) set_flag(regs, FLAG_ZERO);
|
||||
int result = (u8) ((reg & 0x7f) << 1) | old_carry;
|
||||
|
||||
if (!result) {
|
||||
set_flag(regs, FLAG_ZERO);
|
||||
} else {
|
||||
clear_flag(regs, FLAG_ZERO);
|
||||
}
|
||||
clear_flag(regs, FLAG_SIGN);
|
||||
clear_flag(regs, FLAG_HALF_CARRY);
|
||||
if (reg & 0x80) {
|
||||
set_flag(regs, FLAG_CARRY);
|
||||
} else {
|
||||
clear_flag(regs, FLAG_CARRY);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -154,7 +164,7 @@ static u8 rrc(struct cpu *cpu, u8 val)
|
|||
|
||||
static u8 shift_left(struct cpu *cpu, u8 value)
|
||||
{
|
||||
int result = value << 1;
|
||||
u8 result = value << 1;
|
||||
if (result == 0) {
|
||||
set_flag(cpu, FLAG_ZERO);
|
||||
} else {
|
||||
|
@ -172,7 +182,7 @@ static u8 shift_left(struct cpu *cpu, u8 value)
|
|||
|
||||
static u8 shift_right(struct cpu *cpu, u8 value)
|
||||
{
|
||||
int result = (signed) value >> 1;
|
||||
u8 result = (signed char) value >> 1;
|
||||
if (result == 0) {
|
||||
set_flag(cpu, FLAG_ZERO);
|
||||
} else {
|
||||
|
@ -257,13 +267,9 @@ static void and(struct cpu *cpu, u8 value)
|
|||
|
||||
static void add(struct cpu *cpu, u8 value, int with_carry)
|
||||
{
|
||||
u8 sum_trunc;
|
||||
int sum_full = cpu->a + value;
|
||||
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0;
|
||||
if (carry) {
|
||||
sum_full++;
|
||||
}
|
||||
sum_trunc = (u8) sum_full;
|
||||
int sum_full = cpu->a + value + carry;
|
||||
u8 sum_trunc = (u8) sum_full;
|
||||
if (sum_trunc == 0) {
|
||||
set_flag(cpu, FLAG_ZERO);
|
||||
} else {
|
||||
|
@ -285,25 +291,21 @@ static void add(struct cpu *cpu, u8 value, int with_carry)
|
|||
|
||||
static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare)
|
||||
{
|
||||
u8 sum_trunc;
|
||||
int sum_full = cpu->a - value;
|
||||
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0;
|
||||
if (carry) {
|
||||
sum_full--;
|
||||
}
|
||||
sum_trunc = (u8) sum_full;
|
||||
int sum_full = cpu->a - value - carry;
|
||||
u8 sum_trunc = (u8) sum_full;
|
||||
if (!sum_trunc) {
|
||||
set_flag(cpu, FLAG_ZERO);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_ZERO);
|
||||
}
|
||||
set_flag(cpu, FLAG_SIGN);
|
||||
if (value > cpu->a) {
|
||||
if (sum_full < 0) {
|
||||
set_flag(cpu, FLAG_CARRY);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_CARRY);
|
||||
}
|
||||
if (((cpu->a & 0xf) - (value & 0xf)) & 0x10) {
|
||||
if (((cpu->a & 0xf) - (value & 0xf) - carry) & 0x10) {
|
||||
set_flag(cpu, FLAG_HALF_CARRY);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||
|
@ -336,21 +338,22 @@ static u16 pop(struct cpu *cpu)
|
|||
|
||||
static void add16(struct cpu *cpu, u16 src)
|
||||
{
|
||||
clear_flag(cpu, FLAG_SIGN);
|
||||
int total = read_hl(cpu) + src; // promoted to int
|
||||
int trunc = total & 0xffff;
|
||||
clear_flag(cpu, FLAG_SIGN);
|
||||
if (total > 0xffff) {
|
||||
set_flag(cpu, FLAG_CARRY);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_CARRY);
|
||||
}
|
||||
if (((cpu->h & 0xf) + ((src >> 8) & 0xf)) & 0x10) {
|
||||
if (((read_hl(cpu) & 0xfff) + (src & 0xfff)) & 0x1000) {
|
||||
// true if carry from bit 11 to bit 12
|
||||
set_flag(cpu, FLAG_HALF_CARRY);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||
}
|
||||
|
||||
write_hl(cpu, total & 0xffff);
|
||||
write_hl(cpu, trunc);
|
||||
}
|
||||
|
||||
static u8 read_reg(struct cpu *cpu, int index)
|
||||
|
@ -407,6 +410,8 @@ static void extended_insn(struct cpu *cpu, u8 insn)
|
|||
srl,
|
||||
};
|
||||
|
||||
// rl, sla, sra
|
||||
|
||||
#ifdef GB6_DEBUG
|
||||
printf(" %s\n", instructions[insn + 0x100].format);
|
||||
#endif
|
||||
|
@ -473,6 +478,24 @@ static void daa(struct cpu *cpu)
|
|||
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||
}
|
||||
|
||||
static void scf(struct cpu *cpu)
|
||||
{
|
||||
clear_flag(cpu, FLAG_SIGN);
|
||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||
set_flag(cpu, FLAG_CARRY);
|
||||
}
|
||||
|
||||
static void ccf(struct cpu *cpu)
|
||||
{
|
||||
clear_flag(cpu, FLAG_SIGN);
|
||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||
if (flag_isset(cpu, FLAG_CARRY)) {
|
||||
clear_flag(cpu, FLAG_CARRY);
|
||||
} else {
|
||||
set_flag(cpu, FLAG_CARRY);
|
||||
}
|
||||
}
|
||||
|
||||
static u16 handlers[] = { 0x40, 0x48, 0x50, 0x58, 0x60 };
|
||||
|
||||
static u16 check_interrupts(struct cpu *cpu)
|
||||
|
@ -508,10 +531,15 @@ void cpu_step(struct cpu *cpu)
|
|||
intr_dest = check_interrupts(cpu);
|
||||
if (intr_dest) {
|
||||
push(cpu, cpu->pc);
|
||||
cpu->halted = 0;
|
||||
cpu->pc = intr_dest;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->halted) {
|
||||
return;
|
||||
}
|
||||
|
||||
u8 opc = dmg_read(cpu->dmg, cpu->pc);
|
||||
#ifdef GB6_DEBUG
|
||||
printf("0x%04x %s\n", cpu->pc, instructions[opc].format);
|
||||
|
@ -531,6 +559,7 @@ void cpu_step(struct cpu *cpu)
|
|||
break;
|
||||
case 0x0f: // RRCA
|
||||
cpu->a = rrc(cpu, cpu->a);
|
||||
clear_flag(cpu, FLAG_ZERO);
|
||||
break;
|
||||
case 0x10: // STOP
|
||||
cpu->pc++;
|
||||
|
@ -541,6 +570,7 @@ void cpu_step(struct cpu *cpu)
|
|||
break;
|
||||
case 0x07: // RLCA
|
||||
cpu->a = rlc(cpu, cpu->a);
|
||||
clear_flag(cpu, FLAG_ZERO);
|
||||
break;
|
||||
case 0x08: // LD (a16),SP
|
||||
write16(cpu, read16(cpu, cpu->pc), cpu->sp);
|
||||
|
@ -554,16 +584,18 @@ void cpu_step(struct cpu *cpu)
|
|||
break;
|
||||
case 0x17: // RLA
|
||||
cpu->a = rotate_left(cpu, cpu->a);
|
||||
clear_flag(cpu, FLAG_ZERO);
|
||||
break;
|
||||
case 0x1f: // RRA
|
||||
cpu->a = rotate_right(cpu, cpu->a);
|
||||
clear_flag(cpu, FLAG_ZERO);
|
||||
break;
|
||||
|
||||
case 0x37: // SCF
|
||||
set_flag(cpu, FLAG_CARRY);
|
||||
scf(cpu);
|
||||
break;
|
||||
case 0x3f: // CCF
|
||||
clear_flag(cpu, FLAG_CARRY);
|
||||
ccf(cpu);
|
||||
break;
|
||||
|
||||
// incs and decs
|
||||
|
@ -944,6 +976,7 @@ void cpu_step(struct cpu *cpu)
|
|||
break;
|
||||
|
||||
case 0x76: // HALT
|
||||
cpu->halted = 1;
|
||||
break;
|
||||
|
||||
case 0xc1: // POP BC
|
||||
|
|
|
@ -20,6 +20,8 @@ struct cpu
|
|||
u32 cycle_count;
|
||||
u8 interrupt_enable;
|
||||
|
||||
u8 halted;
|
||||
|
||||
struct dmg *dmg;
|
||||
// u8 (*mem_read)(void *, u16);
|
||||
// void (*mem_write)(void *, u16, u8);
|
||||
|
|
30
src/dmg.c
30
src/dmg.c
|
@ -50,8 +50,6 @@ static u8 get_button_state(struct dmg *dmg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int counter;
|
||||
|
||||
u8 dmg_read(void *_dmg, u16 address)
|
||||
{
|
||||
struct dmg *dmg = (struct dmg *) _dmg;
|
||||
|
@ -82,8 +80,13 @@ u8 dmg_read(void *_dmg, u16 address)
|
|||
} else if (address == 0xff00) {
|
||||
return get_button_state(dmg);
|
||||
} else if (address == REG_TIMER_DIV) {
|
||||
counter++;
|
||||
return counter;
|
||||
return (dmg->timer_div & 0xff00) >> 8;
|
||||
} else if (address == REG_TIMER_COUNT) {
|
||||
return dmg->timer_count;
|
||||
} else if (address == REG_TIMER_MOD) {
|
||||
return dmg->timer_mod;
|
||||
} else if (address == REG_TIMER_CONTROL) {
|
||||
return dmg->timer_control;
|
||||
} else if (address == 0xff0f) {
|
||||
return dmg->interrupt_requested;
|
||||
} else if (address == 0xffff) {
|
||||
|
@ -116,6 +119,17 @@ void dmg_write(void *_dmg, u16 address, u8 data)
|
|||
} else if (address < 0xe000) {
|
||||
// printf("write ram %04x %02x\n", address, data);
|
||||
dmg->main_ram[address - 0xc000] = data;
|
||||
} else if (address == REG_TIMER_DIV) {
|
||||
dmg->timer_div = 0;
|
||||
} else if (address == REG_TIMER_COUNT) {
|
||||
printf("write timer count\n");
|
||||
dmg->timer_count = data;
|
||||
} else if (address == REG_TIMER_MOD) {
|
||||
printf("write timer mod\n");
|
||||
dmg->timer_mod = data;
|
||||
} else if (address == REG_TIMER_CONTROL) {
|
||||
printf("write timer control\n");
|
||||
dmg->timer_control = data;
|
||||
} else if (address == 0xFF46) {
|
||||
u16 src = data << 8;
|
||||
int k = 0;
|
||||
|
@ -248,15 +262,13 @@ static void render_objs(struct dmg *dmg)
|
|||
|
||||
static void timer_step(struct dmg *dmg)
|
||||
{
|
||||
dmg->timer_div++;
|
||||
|
||||
if (!(dmg_read(dmg, REG_TIMER_CONTROL) & TIMER_CONTROL_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int passed = dmg->cpu->cycle_count - dmg->last_timer_update;
|
||||
// TODO
|
||||
if (passed < 10000) {
|
||||
return;
|
||||
}
|
||||
|
||||
u8 counter = dmg_read(dmg, REG_TIMER_COUNT);
|
||||
u8 modulo = dmg_read(dmg, REG_TIMER_MOD);
|
||||
|
@ -278,7 +290,7 @@ void dmg_step(void *_dmg)
|
|||
// order of dependencies? i think cpu needs to step first then update
|
||||
// all other hw
|
||||
cpu_step(dmg->cpu);
|
||||
// timer_step(dmg);
|
||||
//timer_step(dmg);
|
||||
|
||||
// each line takes 456 cycles
|
||||
int cycle_diff = dmg->cpu->cycle_count - dmg->last_lcd_update;
|
||||
|
|
|
@ -36,12 +36,16 @@ struct dmg {
|
|||
u32 last_lcd_update;
|
||||
u32 last_timer_update;
|
||||
int joypad_selected;
|
||||
int action_selected; // non-0 if A/B/start/select selected, 0 for directions
|
||||
int action_selected;
|
||||
u8 interrupt_enabled;
|
||||
u8 interrupt_requested;
|
||||
|
||||
u8 joypad;
|
||||
u8 action_buttons;
|
||||
u16 timer_div;
|
||||
u8 timer_count;
|
||||
u8 timer_mod;
|
||||
u8 timer_control;
|
||||
};
|
||||
|
||||
void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom, struct lcd *lcd);
|
||||
|
|
Loading…
Reference in New Issue