Add parsing of ldr1r2 instructions

jsmoo
Nick Krichevsky 2022-04-04 22:18:15 -04:00
parent 92b779d02d
commit af95676b15
3 changed files with 177 additions and 0 deletions

View File

@ -1,3 +1,4 @@
#![warn(clippy::all, clippy::pedantic)]
mod register;
mod run;

View File

@ -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);

View File

@ -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));
}
}