feat: add prefixed BIT opcode
This commit is contained in:
parent
84f13b263b
commit
b8cdc65ca7
2 changed files with 168 additions and 0 deletions
|
@ -1,5 +1,6 @@
|
||||||
mod alu;
|
mod alu;
|
||||||
mod load_store_move;
|
mod load_store_move;
|
||||||
|
mod prefixed;
|
||||||
|
|
||||||
use super::Gameboy;
|
use super::Gameboy;
|
||||||
|
|
||||||
|
@ -57,6 +58,7 @@ pub struct Registers {
|
||||||
pub hold: Option<u16>,
|
pub hold: Option<u16>,
|
||||||
pub opcode_len: Option<u8>,
|
pub opcode_len: Option<u8>,
|
||||||
pub current_opcode: Option<u8>,
|
pub current_opcode: Option<u8>,
|
||||||
|
pub current_prefixed_opcode: Option<u8>,
|
||||||
pub mem_read_hold: Option<u8>,
|
pub mem_read_hold: Option<u8>,
|
||||||
pub mem_op_happened: bool,
|
pub mem_op_happened: bool,
|
||||||
}
|
}
|
||||||
|
@ -199,6 +201,7 @@ pub fn tick_cpu(state: &mut Gameboy) {
|
||||||
0xAD => alu::xor_a_l,
|
0xAD => alu::xor_a_l,
|
||||||
0xAE => alu::xor_a_deref_hl,
|
0xAE => alu::xor_a_deref_hl,
|
||||||
0xAF => alu::xor_a_a,
|
0xAF => alu::xor_a_a,
|
||||||
|
0xCB => prefixed::prefixed_handler,
|
||||||
0xDE => alu::sbc_a_imm_u8,
|
0xDE => alu::sbc_a_imm_u8,
|
||||||
0xEE => alu::xor_a_imm_u8,
|
0xEE => alu::xor_a_imm_u8,
|
||||||
0xF9 => load_store_move::ld_sp_hl,
|
0xF9 => load_store_move::ld_sp_hl,
|
||||||
|
@ -217,6 +220,7 @@ pub fn tick_cpu(state: &mut Gameboy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
state.registers.cycle = 0;
|
state.registers.cycle = 0;
|
||||||
|
state.registers.current_prefixed_opcode = None;
|
||||||
state.registers.current_opcode = None;
|
state.registers.current_opcode = None;
|
||||||
state.registers.opcode_len = None;
|
state.registers.opcode_len = None;
|
||||||
log::trace!("Cycle finished");
|
log::trace!("Cycle finished");
|
||||||
|
|
164
src/gameboy/cpu/prefixed.rs
Normal file
164
src/gameboy/cpu/prefixed.rs
Normal 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);
|
Loading…
Reference in a new issue