Add parsing of ldr1r2 instructions
This commit is contained in:
parent
92b779d02d
commit
af95676b15
|
@ -1,3 +1,4 @@
|
||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
mod register;
|
mod register;
|
||||||
|
mod run;
|
||||||
|
|
|
@ -11,6 +11,18 @@ pub enum Flag {
|
||||||
Carry,
|
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
|
// Combined represents a pair of two registers taht can be acted on as a single
|
||||||
// 16 bit register.
|
// 16 bit register.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -101,6 +113,34 @@ impl Registers {
|
||||||
self.flags |= bit << pos;
|
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
|
/// Get the value of a pair of registers
|
||||||
pub fn get_combined_register(&self, registers: Combined) -> u16 {
|
pub fn get_combined_register(&self, registers: Combined) -> u16 {
|
||||||
let (left_register, right_register) = self.get_register_values_for_combined(registers);
|
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,
|
value: u8,
|
||||||
register: register::Single,
|
register: register::Single,
|
||||||
},
|
},
|
||||||
|
// 3.3.1.2, excluding the (hl) instructions
|
||||||
|
LDr1r2 {
|
||||||
|
dst: register::Single,
|
||||||
|
src: register::Single,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RunnableInstruction {
|
struct RunnableInstruction {
|
||||||
|
@ -37,6 +42,56 @@ impl RunnableInstruction {
|
||||||
0x1E => Self::make_ldnn_data(register::Single::E, data),
|
0x1E => Self::make_ldnn_data(register::Single::E, data),
|
||||||
0x26 => Self::make_ldnn_data(register::Single::H, data),
|
0x26 => Self::make_ldnn_data(register::Single::H, data),
|
||||||
0x2E => Self::make_ldnn_data(register::Single::L, 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}"),
|
_ => panic!("invalid opcode {opcode:0x}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +108,20 @@ impl RunnableInstruction {
|
||||||
&data[2..],
|
&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 {
|
impl Processor {
|
||||||
|
@ -61,6 +130,11 @@ impl Processor {
|
||||||
Instruction::LDnnn { value, register } => {
|
Instruction::LDnnn { value, register } => {
|
||||||
self.registers.set_single_register(register, value);
|
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);
|
self.num_cycles += u64::from(instruction.cycles);
|
||||||
|
@ -93,4 +167,66 @@ mod tests {
|
||||||
processor.registers.get_single_register(expected_register)
|
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 a new issue