Add parsing of ldr1r2 instructions
parent
92b779d02d
commit
af95676b15
|
@ -1,3 +1,4 @@
|
|||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
mod register;
|
||||
mod run;
|
||||
|
|
|
@ -11,6 +11,18 @@ pub enum Flag {
|
|||
Carry,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Single {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
F,
|
||||
H,
|
||||
L,
|
||||
}
|
||||
|
||||
// Combined represents a pair of two registers taht can be acted on as a single
|
||||
// 16 bit register.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
@ -101,6 +113,34 @@ impl Registers {
|
|||
self.flags |= bit << pos;
|
||||
}
|
||||
|
||||
pub fn get_single_register(&self, register: Single) -> u8 {
|
||||
match register {
|
||||
Single::A => self.a,
|
||||
Single::B => self.b,
|
||||
Single::C => self.c,
|
||||
Single::D => self.d,
|
||||
Single::E => self.e,
|
||||
Single::F => self.f,
|
||||
Single::H => self.h,
|
||||
Single::L => self.l,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_single_register(&mut self, register: Single, value: u8) {
|
||||
let register_ref = match register {
|
||||
Single::A => &mut self.a,
|
||||
Single::B => &mut self.b,
|
||||
Single::C => &mut self.c,
|
||||
Single::D => &mut self.d,
|
||||
Single::E => &mut self.e,
|
||||
Single::F => &mut self.f,
|
||||
Single::H => &mut self.h,
|
||||
Single::L => &mut self.l,
|
||||
};
|
||||
|
||||
*register_ref = value;
|
||||
}
|
||||
|
||||
/// Get the value of a pair of registers
|
||||
pub fn get_combined_register(&self, registers: Combined) -> u16 {
|
||||
let (left_register, right_register) = self.get_register_values_for_combined(registers);
|
||||
|
|
136
src/run.rs
136
src/run.rs
|
@ -16,6 +16,11 @@ pub enum Instruction {
|
|||
value: u8,
|
||||
register: register::Single,
|
||||
},
|
||||
// 3.3.1.2, excluding the (hl) instructions
|
||||
LDr1r2 {
|
||||
dst: register::Single,
|
||||
src: register::Single,
|
||||
},
|
||||
}
|
||||
|
||||
struct RunnableInstruction {
|
||||
|
@ -37,6 +42,56 @@ impl RunnableInstruction {
|
|||
0x1E => Self::make_ldnn_data(register::Single::E, data),
|
||||
0x26 => Self::make_ldnn_data(register::Single::H, data),
|
||||
0x2E => Self::make_ldnn_data(register::Single::L, data),
|
||||
|
||||
0x7F => Self::make_ldr1r2_data(register::Single::A, register::Single::A, data),
|
||||
0x78 => Self::make_ldr1r2_data(register::Single::A, register::Single::B, data),
|
||||
0x79 => Self::make_ldr1r2_data(register::Single::A, register::Single::C, data),
|
||||
0x7A => Self::make_ldr1r2_data(register::Single::A, register::Single::D, data),
|
||||
0x7B => Self::make_ldr1r2_data(register::Single::A, register::Single::E, data),
|
||||
0x7C => Self::make_ldr1r2_data(register::Single::A, register::Single::H, data),
|
||||
0x7D => Self::make_ldr1r2_data(register::Single::A, register::Single::L, data),
|
||||
// 0x7E skipped
|
||||
0x40 => Self::make_ldr1r2_data(register::Single::B, register::Single::B, data),
|
||||
0x41 => Self::make_ldr1r2_data(register::Single::B, register::Single::C, data),
|
||||
0x42 => Self::make_ldr1r2_data(register::Single::B, register::Single::D, data),
|
||||
0x43 => Self::make_ldr1r2_data(register::Single::B, register::Single::E, data),
|
||||
0x44 => Self::make_ldr1r2_data(register::Single::B, register::Single::H, data),
|
||||
0x45 => Self::make_ldr1r2_data(register::Single::B, register::Single::L, data),
|
||||
// 0x46 skiipped
|
||||
0x48 => Self::make_ldr1r2_data(register::Single::C, register::Single::B, data),
|
||||
0x49 => Self::make_ldr1r2_data(register::Single::C, register::Single::C, data),
|
||||
0x4A => Self::make_ldr1r2_data(register::Single::C, register::Single::D, data),
|
||||
0x4B => Self::make_ldr1r2_data(register::Single::C, register::Single::E, data),
|
||||
0x4C => Self::make_ldr1r2_data(register::Single::C, register::Single::H, data),
|
||||
0x4D => Self::make_ldr1r2_data(register::Single::C, register::Single::L, data),
|
||||
// 0x4E skipped
|
||||
0x50 => Self::make_ldr1r2_data(register::Single::D, register::Single::B, data),
|
||||
0x51 => Self::make_ldr1r2_data(register::Single::D, register::Single::C, data),
|
||||
0x52 => Self::make_ldr1r2_data(register::Single::D, register::Single::D, data),
|
||||
0x53 => Self::make_ldr1r2_data(register::Single::D, register::Single::E, data),
|
||||
0x54 => Self::make_ldr1r2_data(register::Single::D, register::Single::H, data),
|
||||
0x55 => Self::make_ldr1r2_data(register::Single::D, register::Single::L, data),
|
||||
// 0x56 skipped
|
||||
0x58 => Self::make_ldr1r2_data(register::Single::E, register::Single::B, data),
|
||||
0x59 => Self::make_ldr1r2_data(register::Single::E, register::Single::C, data),
|
||||
0x5A => Self::make_ldr1r2_data(register::Single::E, register::Single::D, data),
|
||||
0x5B => Self::make_ldr1r2_data(register::Single::E, register::Single::E, data),
|
||||
0x5C => Self::make_ldr1r2_data(register::Single::E, register::Single::H, data),
|
||||
0x5D => Self::make_ldr1r2_data(register::Single::E, register::Single::L, data),
|
||||
// 0x5E skipped
|
||||
0x60 => Self::make_ldr1r2_data(register::Single::H, register::Single::B, data),
|
||||
0x61 => Self::make_ldr1r2_data(register::Single::H, register::Single::C, data),
|
||||
0x62 => Self::make_ldr1r2_data(register::Single::H, register::Single::D, data),
|
||||
0x63 => Self::make_ldr1r2_data(register::Single::H, register::Single::E, data),
|
||||
0x64 => Self::make_ldr1r2_data(register::Single::H, register::Single::H, data),
|
||||
0x65 => Self::make_ldr1r2_data(register::Single::H, register::Single::L, data),
|
||||
// 0x66 skipped
|
||||
0x68 => Self::make_ldr1r2_data(register::Single::L, register::Single::B, data),
|
||||
0x69 => Self::make_ldr1r2_data(register::Single::L, register::Single::C, data),
|
||||
0x6A => Self::make_ldr1r2_data(register::Single::L, register::Single::D, data),
|
||||
0x6B => Self::make_ldr1r2_data(register::Single::L, register::Single::E, data),
|
||||
0x6C => Self::make_ldr1r2_data(register::Single::L, register::Single::H, data),
|
||||
0x6D => Self::make_ldr1r2_data(register::Single::L, register::Single::L, data),
|
||||
_ => panic!("invalid opcode {opcode:0x}"),
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +108,20 @@ impl RunnableInstruction {
|
|||
&data[2..],
|
||||
)
|
||||
}
|
||||
|
||||
fn make_ldr1r2_data(
|
||||
dst: register::Single,
|
||||
src: register::Single,
|
||||
data: &[u8],
|
||||
) -> (RunnableInstruction, &[u8]) {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::LDr1r2 { dst, src },
|
||||
cycles: 4,
|
||||
},
|
||||
&data[1..],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Processor {
|
||||
|
@ -61,6 +130,11 @@ impl Processor {
|
|||
Instruction::LDnnn { value, register } => {
|
||||
self.registers.set_single_register(register, value);
|
||||
}
|
||||
Instruction::LDr1r2 { dst, src } => {
|
||||
dbg!(dst, src);
|
||||
let src_value = self.registers.get_single_register(src);
|
||||
self.registers.set_single_register(dst, src_value);
|
||||
}
|
||||
}
|
||||
|
||||
self.num_cycles += u64::from(instruction.cycles);
|
||||
|
@ -93,4 +167,66 @@ mod tests {
|
|||
processor.registers.get_single_register(expected_register)
|
||||
);
|
||||
}
|
||||
|
||||
// lol going from a register to itself is kind of a weird thing to test
|
||||
#[test_case(0x7F, register::Single::A, register::Single::A)]
|
||||
#[test_case(0x78, register::Single::A, register::Single::B)]
|
||||
#[test_case(0x79, register::Single::A, register::Single::C)]
|
||||
#[test_case(0x7A, register::Single::A, register::Single::D)]
|
||||
#[test_case(0x7B, register::Single::A, register::Single::E)]
|
||||
#[test_case(0x7C, register::Single::A, register::Single::H)]
|
||||
#[test_case(0x7D, register::Single::A, register::Single::L)]
|
||||
#[test_case(0x40, register::Single::B, register::Single::B)]
|
||||
#[test_case(0x41, register::Single::B, register::Single::C)]
|
||||
#[test_case(0x42, register::Single::B, register::Single::D)]
|
||||
#[test_case(0x43, register::Single::B, register::Single::E)]
|
||||
#[test_case(0x44, register::Single::B, register::Single::H)]
|
||||
#[test_case(0x45, register::Single::B, register::Single::L)]
|
||||
#[test_case(0x48, register::Single::C, register::Single::B)]
|
||||
#[test_case(0x49, register::Single::C, register::Single::C)]
|
||||
#[test_case(0x4A, register::Single::C, register::Single::D)]
|
||||
#[test_case(0x4B, register::Single::C, register::Single::E)]
|
||||
#[test_case(0x4C, register::Single::C, register::Single::H)]
|
||||
#[test_case(0x4D, register::Single::C, register::Single::L)]
|
||||
#[test_case(0x50, register::Single::D, register::Single::B)]
|
||||
#[test_case(0x51, register::Single::D, register::Single::C)]
|
||||
#[test_case(0x52, register::Single::D, register::Single::D)]
|
||||
#[test_case(0x53, register::Single::D, register::Single::E)]
|
||||
#[test_case(0x54, register::Single::D, register::Single::H)]
|
||||
#[test_case(0x55, register::Single::D, register::Single::L)]
|
||||
#[test_case(0x58, register::Single::E, register::Single::B)]
|
||||
#[test_case(0x59, register::Single::E, register::Single::C)]
|
||||
#[test_case(0x5A, register::Single::E, register::Single::D)]
|
||||
#[test_case(0x5B, register::Single::E, register::Single::E)]
|
||||
#[test_case(0x5C, register::Single::E, register::Single::H)]
|
||||
#[test_case(0x5D, register::Single::E, register::Single::L)]
|
||||
#[test_case(0x60, register::Single::H, register::Single::B)]
|
||||
#[test_case(0x61, register::Single::H, register::Single::C)]
|
||||
#[test_case(0x62, register::Single::H, register::Single::D)]
|
||||
#[test_case(0x63, register::Single::H, register::Single::E)]
|
||||
#[test_case(0x64, register::Single::H, register::Single::H)]
|
||||
#[test_case(0x65, register::Single::H, register::Single::L)]
|
||||
#[test_case(0x68, register::Single::L, register::Single::B)]
|
||||
#[test_case(0x69, register::Single::L, register::Single::C)]
|
||||
#[test_case(0x6A, register::Single::L, register::Single::D)]
|
||||
#[test_case(0x6B, register::Single::L, register::Single::E)]
|
||||
#[test_case(0x6C, register::Single::L, register::Single::H)]
|
||||
#[test_case(0x6D, register::Single::L, register::Single::L)]
|
||||
fn test_load_register(
|
||||
ld_opcode: u8,
|
||||
dst_register: register::Single,
|
||||
src_register: register::Single,
|
||||
) {
|
||||
let mut processor = Processor::default();
|
||||
processor.registers.set_single_register(src_register, 0x45);
|
||||
|
||||
let data = [ld_opcode, 0x00];
|
||||
let (ins, extra_data) = RunnableInstruction::from_data(&data);
|
||||
|
||||
// assert our extra data after the instruction is returned
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
|
||||
processor.run(&ins);
|
||||
assert_eq!(0x45, processor.registers.get_single_register(dst_register));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue