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,
|
||||
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,
|
||||
|
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -426,7 +426,7 @@ macro_rules! define_push_pop_reg {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn [<pop_ $reg>](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);
|
||||
define_push_pop_reg!(af);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue