diff --git a/src/cpu.c b/src/cpu.c index 6aec086..6db4f04 100644 --- a/src/cpu.c +++ b/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 diff --git a/src/cpu.h b/src/cpu.h index 466e99f..36c676f 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -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); diff --git a/src/dmg.c b/src/dmg.c index a336f2a..60c37e0 100644 --- a/src/dmg.c +++ b/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; diff --git a/src/dmg.h b/src/dmg.h index c86477f..834800f 100644 --- a/src/dmg.h +++ b/src/dmg.h @@ -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);