diff --git a/src/gameboy/cpu.rs b/src/gameboy/cpu.rs index eff9468..dcc2734 100644 --- a/src/gameboy/cpu.rs +++ b/src/gameboy/cpu.rs @@ -132,6 +132,7 @@ pub fn tick_cpu(state: &mut Gameboy) { 0x14 => alu::inc_d, 0x15 => alu::dec_d, 0x16 => load_store_move::ld_d_imm_u8, + 0x17 => alu::rla, 0x18 => flow::jr_i8, 0x1a => load_store_move::ld_a_deref_de, 0x1c => alu::inc_e, @@ -222,6 +223,14 @@ pub fn tick_cpu(state: &mut Gameboy) { 0x7d => load_store_move::ld_a_l, 0x7e => load_store_move::ld_a_deref_hl, 0x7f => load_store_move::ld_a_a, + 0x90 => alu::sub_a_b, + 0x91 => alu::sub_a_c, + 0x92 => alu::sub_a_d, + 0x93 => alu::sub_a_e, + 0x94 => alu::sub_a_h, + 0x95 => alu::sub_a_l, + 0x96 => alu::sub_a_deref_hl, + 0x97 => alu::sub_a_a, 0x98 => alu::sbc_a_b, 0x99 => alu::sbc_a_c, 0x9A => alu::sbc_a_d, @@ -255,6 +264,7 @@ pub fn tick_cpu(state: &mut Gameboy) { 0xD2 => flow::jp_nc_u16, 0xD4 => flow::call_nc_u16, 0xD5 => load_store_move::push_de, + 0xD6 => alu::sub_a_imm_u8, 0xD8 => flow::ret_c, 0xD9 => flow::reti, 0xDA => flow::jp_c_u16, diff --git a/src/gameboy/cpu/alu.rs b/src/gameboy/cpu/alu.rs index 51fcfec..3c5f889 100644 --- a/src/gameboy/cpu/alu.rs +++ b/src/gameboy/cpu/alu.rs @@ -75,29 +75,6 @@ macro_rules! define_xor_reg { }; } -macro_rules! define_sbc_reg { - ($reg:ident) => { - paste::paste! { - pub fn [](state: &mut Gameboy) -> CycleResult { - match state.registers.cycle { - 0 => { - let CarryResult { result, half_carry, carry } = sub_with_carry(state.registers.a, state.registers.$reg, state.registers.get_carry()); - - state.registers.a = result; - state.registers.set_zero(result == 0); - state.registers.set_subtract(true); - state.registers.set_half_carry(half_carry); - state.registers.set_carry(carry); - state.registers.opcode_bytecount = Some(1); - CycleResult::Finished - }, - _ => unreachable!(), - } - } - } - }; -} - define_xor_reg!(a); define_xor_reg!(b); define_xor_reg!(c); @@ -144,6 +121,29 @@ pub fn xor_a_imm_u8(state: &mut Gameboy) -> CycleResult { } } +macro_rules! define_sbc_reg { + ($reg:ident) => { + paste::paste! { + pub fn [](state: &mut Gameboy) -> CycleResult { + match state.registers.cycle { + 0 => { + let CarryResult { result, half_carry, carry } = sub_with_carry(state.registers.a, state.registers.$reg, state.registers.get_carry()); + + state.registers.a = result; + state.registers.set_zero(result == 0); + state.registers.set_subtract(true); + state.registers.set_half_carry(half_carry); + state.registers.set_carry(carry); + state.registers.opcode_bytecount = Some(1); + CycleResult::Finished + }, + _ => unreachable!(), + } + } + } + }; +} + define_sbc_reg!(a); define_sbc_reg!(b); define_sbc_reg!(c); @@ -202,6 +202,81 @@ pub fn sbc_a_imm_u8(state: &mut Gameboy) -> CycleResult { } } +macro_rules! define_sub_reg { + ($reg:ident) => { + paste::paste! { + pub fn [](state: &mut Gameboy) -> CycleResult { + match state.registers.cycle { + 0 => { + let CarryResult { result, half_carry, carry } = sub(state.registers.a, state.registers.$reg); + + state.registers.a = result; + state.registers.set_zero(result == 0); + state.registers.set_subtract(true); + state.registers.set_half_carry(half_carry); + state.registers.set_carry(carry); + state.registers.opcode_bytecount = Some(1); + CycleResult::Finished + }, + _ => unreachable!(), + } + } + } + }; +} + +define_sub_reg!(a); +define_sub_reg!(b); +define_sub_reg!(c); +define_sub_reg!(d); +define_sub_reg!(e); +define_sub_reg!(h); +define_sub_reg!(l); + +pub fn sub_a_deref_hl(state: &mut Gameboy) -> CycleResult { + match state.registers.cycle { + 0 => { + state.cpu_read_u8(state.registers.get_hl()); + CycleResult::NeedsMore + } + 1 => { + let CarryResult { result, half_carry, carry } = + sub(state.registers.a, state.registers.take_mem()); + + state.registers.a = result; + state.registers.set_zero(result == 0); + state.registers.set_subtract(true); + state.registers.set_half_carry(half_carry); + state.registers.set_carry(carry); + state.registers.opcode_bytecount = Some(1); + CycleResult::Finished + } + _ => unreachable!(), + } +} + +pub fn sub_a_imm_u8(state: &mut Gameboy) -> CycleResult { + match state.registers.cycle { + 0 => { + state.cpu_read_u8(state.registers.pc + 1); + CycleResult::NeedsMore + } + 1 => { + let CarryResult { result, half_carry, carry } = + sub(state.registers.a, state.registers.take_mem()); + + state.registers.a = result; + state.registers.set_zero(result == 0); + state.registers.set_subtract(true); + state.registers.set_half_carry(half_carry); + state.registers.set_carry(carry); + state.registers.opcode_bytecount = Some(1); + CycleResult::Finished + } + _ => unreachable!(), + } +} + macro_rules! define_inc_reg { ($reg:ident) => { paste::paste! { @@ -305,3 +380,25 @@ pub fn dec_deref_hl(state: &mut Gameboy) -> CycleResult { _ => unimplemented!(), } } + +pub fn rla(state: &mut Gameboy) -> CycleResult { + match state.registers.cycle { + 0 => { + let carry = state.registers.a >> 7 == 1; + state.registers.a <<= 1; + + if state.registers.get_carry() { + state.registers.a |= 1; + } + + state.registers.set_zero(false); + state.registers.set_subtract(false); + state.registers.set_half_carry(false); + state.registers.set_carry(carry); + + state.registers.opcode_bytecount = Some(1); + CycleResult::Finished + } + _ => unreachable!(), + } +} diff --git a/src/gameboy/cpu/load_store_move.rs b/src/gameboy/cpu/load_store_move.rs index 614b955..15ee243 100644 --- a/src/gameboy/cpu/load_store_move.rs +++ b/src/gameboy/cpu/load_store_move.rs @@ -426,7 +426,7 @@ macro_rules! define_push_pop_reg { _ => unreachable!(), } } - + pub fn [](state: &mut Gameboy) -> CycleResult { match state.registers.cycle { 0 => { @@ -455,4 +455,4 @@ macro_rules! define_push_pop_reg { define_push_pop_reg!(bc); define_push_pop_reg!(de); define_push_pop_reg!(hl); -define_push_pop_reg!(af); \ No newline at end of file +define_push_pop_reg!(af); diff --git a/src/gameboy/cpu/prefixed.rs b/src/gameboy/cpu/prefixed.rs index e3304d6..9c5ca77 100644 --- a/src/gameboy/cpu/prefixed.rs +++ b/src/gameboy/cpu/prefixed.rs @@ -17,6 +17,13 @@ pub fn prefixed_handler(state: &mut Gameboy) -> CycleResult { }; let res: CycleResult = match opcode { + 0x10 => rl_b, + 0x11 => rl_c, + 0x12 => rl_d, + 0x13 => rl_e, + 0x14 => rl_h, + 0x15 => rl_l, + 0x17 => rl_a, 0x40 => bit_0_b, 0x41 => bit_0_c, 0x42 => bit_0_d, @@ -162,3 +169,33 @@ define_bit_deref_hl!(4); define_bit_deref_hl!(5); define_bit_deref_hl!(6); define_bit_deref_hl!(7); + +macro_rules! define_rl_reg { + ($reg:ident) => { + paste::paste! { + pub fn [](state: &mut Gameboy) -> CycleResult { + match state.registers.cycle { + 1 => { + let (res, carry) = state.registers.$reg.overflowing_shl(1); + state.registers.$reg = res; + state.registers.set_zero(res == 0); + state.registers.set_subtract(false); + state.registers.set_half_carry(false); + state.registers.set_carry(carry); + state.registers.opcode_bytecount = Some(2); + CycleResult::Finished + }, + _ => unreachable!(), + } + } + } + }; +} + +define_rl_reg!(b); +define_rl_reg!(c); +define_rl_reg!(d); +define_rl_reg!(e); +define_rl_reg!(h); +define_rl_reg!(l); +define_rl_reg!(a);