feat: add prefixed BIT opcode

This commit is contained in:
EliseZeroTwo 2021-11-28 12:27:17 +01:00
parent 84f13b263b
commit b8cdc65ca7
No known key found for this signature in database
GPG key ID: E6D56A6F7B7991DE
2 changed files with 168 additions and 0 deletions

View file

@ -1,5 +1,6 @@
mod alu;
mod load_store_move;
mod prefixed;
use super::Gameboy;
@ -57,6 +58,7 @@ pub struct Registers {
pub hold: Option<u16>,
pub opcode_len: Option<u8>,
pub current_opcode: Option<u8>,
pub current_prefixed_opcode: Option<u8>,
pub mem_read_hold: Option<u8>,
pub mem_op_happened: bool,
}
@ -199,6 +201,7 @@ pub fn tick_cpu(state: &mut Gameboy) {
0xAD => alu::xor_a_l,
0xAE => alu::xor_a_deref_hl,
0xAF => alu::xor_a_a,
0xCB => prefixed::prefixed_handler,
0xDE => alu::sbc_a_imm_u8,
0xEE => alu::xor_a_imm_u8,
0xF9 => load_store_move::ld_sp_hl,
@ -217,6 +220,7 @@ pub fn tick_cpu(state: &mut Gameboy) {
}
state.registers.cycle = 0;
state.registers.current_prefixed_opcode = None;
state.registers.current_opcode = None;
state.registers.opcode_len = None;
log::trace!("Cycle finished");

164
src/gameboy/cpu/prefixed.rs Normal file
View file

@ -0,0 +1,164 @@
use super::CycleResult;
use crate::gameboy::Gameboy;
pub fn prefixed_handler(state: &mut Gameboy) -> CycleResult {
let opcode = match state.registers.current_prefixed_opcode {
Some(prefixed_opcode) => prefixed_opcode,
None => match state.registers.mem_read_hold.take() {
Some(opcode) => {
state.registers.current_prefixed_opcode = Some(opcode);
opcode
}
None => {
state.cpu_read_u8(state.registers.pc.overflowing_add(1).0);
return CycleResult::NeedsMore;
}
},
};
let res: CycleResult = match opcode {
0x40 => bit_0_b,
0x41 => bit_0_c,
0x42 => bit_0_d,
0x43 => bit_0_e,
0x44 => bit_0_h,
0x45 => bit_0_l,
0x46 => bit_0_deref_hl,
0x47 => bit_0_a,
0x48 => bit_1_b,
0x49 => bit_1_c,
0x4a => bit_1_d,
0x4b => bit_1_e,
0x4c => bit_1_h,
0x4d => bit_1_l,
0x4e => bit_1_deref_hl,
0x4f => bit_1_a,
0x50 => bit_2_b,
0x51 => bit_2_c,
0x52 => bit_2_d,
0x53 => bit_2_e,
0x54 => bit_2_h,
0x55 => bit_2_l,
0x56 => bit_2_deref_hl,
0x57 => bit_2_a,
0x58 => bit_3_b,
0x59 => bit_3_c,
0x5a => bit_3_d,
0x5b => bit_3_e,
0x5c => bit_3_h,
0x5d => bit_3_l,
0x5e => bit_3_deref_hl,
0x5f => bit_3_a,
0x60 => bit_4_b,
0x61 => bit_4_c,
0x62 => bit_4_d,
0x63 => bit_4_e,
0x64 => bit_4_h,
0x65 => bit_4_l,
0x66 => bit_4_deref_hl,
0x67 => bit_4_a,
0x68 => bit_5_b,
0x69 => bit_5_c,
0x6a => bit_5_d,
0x6b => bit_5_e,
0x6c => bit_5_h,
0x6d => bit_5_l,
0x6e => bit_5_deref_hl,
0x6f => bit_5_a,
0x70 => bit_6_b,
0x71 => bit_6_c,
0x72 => bit_6_d,
0x73 => bit_6_e,
0x74 => bit_6_h,
0x75 => bit_6_l,
0x76 => bit_6_deref_hl,
0x77 => bit_6_a,
0x78 => bit_7_b,
0x79 => bit_7_c,
0x7a => bit_7_d,
0x7b => bit_7_e,
0x7c => bit_7_h,
0x7d => bit_7_l,
0x7e => bit_7_deref_hl,
0x7f => bit_7_a,
unknown => panic!(
"Unrecognized prefixed opcode: {:#X}\nRegisters: {:#?}",
unknown, state.registers
),
}(state);
res
}
macro_rules! define_bit_reg {
($bit:literal, $reg:ident) => {
paste::paste! {
pub fn [<bit_ $bit _ $reg>](state: &mut Gameboy) -> CycleResult {
match state.registers.cycle {
1 => {
state.registers.set_zero(state.registers.$reg & (1 << $bit) == 0);
state.registers.set_subtract(false);
state.registers.set_half_carry(true);
state.registers.opcode_len = Some(2);
CycleResult::Finished
}
_ => unreachable!(),
}
}
}
};
}
macro_rules! define_bits_reg {
($reg:ident) => {
define_bit_reg!(0, $reg);
define_bit_reg!(1, $reg);
define_bit_reg!(2, $reg);
define_bit_reg!(3, $reg);
define_bit_reg!(4, $reg);
define_bit_reg!(5, $reg);
define_bit_reg!(6, $reg);
define_bit_reg!(7, $reg);
};
}
define_bits_reg!(b);
define_bits_reg!(c);
define_bits_reg!(d);
define_bits_reg!(e);
define_bits_reg!(h);
define_bits_reg!(l);
define_bits_reg!(a);
macro_rules! define_bit_deref_hl {
($bit:literal) => {
paste::paste! {
pub fn [<bit_ $bit _deref_hl>](state: &mut Gameboy) -> CycleResult {
match state.registers.cycle {
1 => {
state.cpu_read_u8(state.registers.get_hl());
CycleResult::NeedsMore
},
2 => {
let mem_read = state.registers.take_mem();
state.registers.set_zero(mem_read & (1 << $bit) == 0);
state.registers.set_subtract(false);
state.registers.set_half_carry(true);
state.registers.opcode_len = Some(2);
CycleResult::Finished
}
_ => unreachable!(),
}
}
}
};
}
define_bit_deref_hl!(0);
define_bit_deref_hl!(1);
define_bit_deref_hl!(2);
define_bit_deref_hl!(3);
define_bit_deref_hl!(4);
define_bit_deref_hl!(5);
define_bit_deref_hl!(6);
define_bit_deref_hl!(7);