feat: add rla and sub opcodes
This commit is contained in:
parent
c2ff461ae8
commit
4f32a7ee3f
4 changed files with 169 additions and 25 deletions
|
@ -132,6 +132,7 @@ pub fn tick_cpu(state: &mut Gameboy) {
|
||||||
0x14 => alu::inc_d,
|
0x14 => alu::inc_d,
|
||||||
0x15 => alu::dec_d,
|
0x15 => alu::dec_d,
|
||||||
0x16 => load_store_move::ld_d_imm_u8,
|
0x16 => load_store_move::ld_d_imm_u8,
|
||||||
|
0x17 => alu::rla,
|
||||||
0x18 => flow::jr_i8,
|
0x18 => flow::jr_i8,
|
||||||
0x1a => load_store_move::ld_a_deref_de,
|
0x1a => load_store_move::ld_a_deref_de,
|
||||||
0x1c => alu::inc_e,
|
0x1c => alu::inc_e,
|
||||||
|
@ -222,6 +223,14 @@ pub fn tick_cpu(state: &mut Gameboy) {
|
||||||
0x7d => load_store_move::ld_a_l,
|
0x7d => load_store_move::ld_a_l,
|
||||||
0x7e => load_store_move::ld_a_deref_hl,
|
0x7e => load_store_move::ld_a_deref_hl,
|
||||||
0x7f => load_store_move::ld_a_a,
|
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,
|
0x98 => alu::sbc_a_b,
|
||||||
0x99 => alu::sbc_a_c,
|
0x99 => alu::sbc_a_c,
|
||||||
0x9A => alu::sbc_a_d,
|
0x9A => alu::sbc_a_d,
|
||||||
|
@ -255,6 +264,7 @@ pub fn tick_cpu(state: &mut Gameboy) {
|
||||||
0xD2 => flow::jp_nc_u16,
|
0xD2 => flow::jp_nc_u16,
|
||||||
0xD4 => flow::call_nc_u16,
|
0xD4 => flow::call_nc_u16,
|
||||||
0xD5 => load_store_move::push_de,
|
0xD5 => load_store_move::push_de,
|
||||||
|
0xD6 => alu::sub_a_imm_u8,
|
||||||
0xD8 => flow::ret_c,
|
0xD8 => flow::ret_c,
|
||||||
0xD9 => flow::reti,
|
0xD9 => flow::reti,
|
||||||
0xDA => flow::jp_c_u16,
|
0xDA => flow::jp_c_u16,
|
||||||
|
|
|
@ -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!(a);
|
||||||
define_xor_reg!(b);
|
define_xor_reg!(b);
|
||||||
define_xor_reg!(c);
|
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!(a);
|
||||||
define_sbc_reg!(b);
|
define_sbc_reg!(b);
|
||||||
define_sbc_reg!(c);
|
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 {
|
macro_rules! define_inc_reg {
|
||||||
($reg:ident) => {
|
($reg:ident) => {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
|
@ -305,3 +380,25 @@ pub fn dec_deref_hl(state: &mut Gameboy) -> CycleResult {
|
||||||
_ => unimplemented!(),
|
_ => 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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,13 @@ pub fn prefixed_handler(state: &mut Gameboy) -> CycleResult {
|
||||||
};
|
};
|
||||||
|
|
||||||
let res: CycleResult = match opcode {
|
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,
|
0x40 => bit_0_b,
|
||||||
0x41 => bit_0_c,
|
0x41 => bit_0_c,
|
||||||
0x42 => bit_0_d,
|
0x42 => bit_0_d,
|
||||||
|
@ -162,3 +169,33 @@ define_bit_deref_hl!(4);
|
||||||
define_bit_deref_hl!(5);
|
define_bit_deref_hl!(5);
|
||||||
define_bit_deref_hl!(6);
|
define_bit_deref_hl!(6);
|
||||||
define_bit_deref_hl!(7);
|
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);
|
||||||
|
|
Loading…
Reference in a new issue