feat: add rla and sub opcodes

This commit is contained in:
EliseZeroTwo 2021-12-02 16:14:03 +01:00
parent c2ff461ae8
commit 4f32a7ee3f
No known key found for this signature in database
GPG key ID: E6D56A6F7B7991DE
4 changed files with 169 additions and 25 deletions

View file

@ -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,

View file

@ -75,29 +75,6 @@ macro_rules! define_xor_reg {
};
}
macro_rules! define_sbc_reg {
($reg:ident) => {
paste::paste! {
pub fn [<sbc_a_ $reg>](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 [<sbc_a_ $reg>](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 [<sub_a_ $reg>](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!(),
}
}

View file

@ -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 [<rl_ $reg>](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);