Implement load + inc/dec opcodes
parent
9a7f1ed093
commit
af38d1edf4
54
src/run.rs
54
src/run.rs
|
@ -107,6 +107,32 @@ impl Processor {
|
|||
"invalid offset stored in dst register ({offset_register})"
|
||||
);
|
||||
}
|
||||
Instruction::LDToRegisterAddressThenDec { dst, src } => {
|
||||
let value = self.registers.get_single_register(src);
|
||||
let dst_address = self.registers.get_combined_register(dst);
|
||||
|
||||
let memory_value = self.memory.set(dst_address.into(), value);
|
||||
|
||||
assert!(
|
||||
memory_value.is_some(),
|
||||
"invalid address stored in ({src}): {dst_address:X}"
|
||||
);
|
||||
|
||||
self.registers.set_combined_register(dst, dst_address - 1);
|
||||
}
|
||||
Instruction::LDToRegisterAddressThenInc { dst, src } => {
|
||||
let value = self.registers.get_single_register(src);
|
||||
let dst_address = self.registers.get_combined_register(dst);
|
||||
|
||||
let memory_value = self.memory.set(dst_address.into(), value);
|
||||
|
||||
assert!(
|
||||
memory_value.is_some(),
|
||||
"invalid address stored in ({src}): {dst_address:X}"
|
||||
);
|
||||
|
||||
self.registers.set_combined_register(dst, dst_address + 1);
|
||||
}
|
||||
}
|
||||
|
||||
self.num_cycles += u64::from(instruction.cycles);
|
||||
|
@ -354,4 +380,32 @@ mod tests {
|
|||
processor.run(&ins);
|
||||
assert_eq!(Some(10), processor.memory.get(0xFF64));
|
||||
}
|
||||
|
||||
#[test_case(0x32, 0x64, 0x63)]
|
||||
#[test_case(0x2A, 0x64, 0x65)]
|
||||
fn test_load_to_register_then_do_arithmetic(
|
||||
opcode: u8,
|
||||
hl_value_before: u16,
|
||||
hl_value_after: u16,
|
||||
) {
|
||||
let mut processor = Processor::default();
|
||||
processor
|
||||
.registers
|
||||
.set_combined_register(register::Combined::HL, hl_value_before);
|
||||
processor.registers.a = 10;
|
||||
|
||||
let data = [opcode, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run(&ins);
|
||||
assert_eq!(Some(10), processor.memory.get(hl_value_before.into()));
|
||||
assert_eq!(
|
||||
hl_value_after,
|
||||
processor
|
||||
.registers
|
||||
.get_combined_register(register::Combined::HL)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,20 @@ pub enum Instruction {
|
|||
LDnToHLAddress {
|
||||
value: u8,
|
||||
},
|
||||
// 3.3.1.{10,11,12}
|
||||
LDToRegisterAddressThenDec {
|
||||
src: register::Single,
|
||||
// The destination, unlike some other destination instructions, refers to a register
|
||||
// whose address will be dereferenced (and then decremented after the load)
|
||||
dst: register::Combined,
|
||||
},
|
||||
// 3.3.1.{13,14,15}
|
||||
LDToRegisterAddressThenInc {
|
||||
src: register::Single,
|
||||
// The destination, unlike some other destination instructions, refers to a register
|
||||
// whose address will be dereferenced (and then incremented after the load)
|
||||
dst: register::Combined,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct RunnableInstruction {
|
||||
|
|
|
@ -12,6 +12,7 @@ impl OpcodeParser for Memory8BitLoadParser {
|
|||
parse_load_from_register_to_address,
|
||||
parse_load_from_address_to_register,
|
||||
parse_load_immediate_instructions,
|
||||
parse_load_from_register_to_address_then_do_arithmetic,
|
||||
];
|
||||
|
||||
for parse_func in parse_funcs {
|
||||
|
@ -82,6 +83,25 @@ fn parse_load_immediate_instructions(data: &[u8]) -> ParseResult {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_load_from_register_to_address_then_do_arithmetic(data: &[u8]) -> ParseResult {
|
||||
let opcode = parse::get_opcode_from_data(data)?;
|
||||
match opcode {
|
||||
0x32 => make_ld_to_address_then_do_arithmetic(
|
||||
register::Combined::HL,
|
||||
register::Single::A,
|
||||
|dst, src| Instruction::LDToRegisterAddressThenDec { dst, src },
|
||||
data,
|
||||
),
|
||||
0x2A => make_ld_to_address_then_do_arithmetic(
|
||||
register::Combined::HL,
|
||||
register::Single::A,
|
||||
|dst, src| Instruction::LDToRegisterAddressThenInc { dst, src },
|
||||
data,
|
||||
),
|
||||
_ => Err(Error::UnknownOpcode(opcode)),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_ld_from_register_address(
|
||||
dst: register::Single,
|
||||
src: register::Combined,
|
||||
|
@ -206,3 +226,25 @@ fn make_ld_to_memory_relative_to_io_register_start(
|
|||
})
|
||||
.ok_or(Error::NoData)
|
||||
}
|
||||
|
||||
fn make_ld_to_address_then_do_arithmetic<
|
||||
F: Fn(register::Combined, register::Single) -> Instruction,
|
||||
>(
|
||||
dst: register::Combined,
|
||||
src: register::Single,
|
||||
make: F,
|
||||
data: &[u8],
|
||||
) -> ParseResult {
|
||||
data.get(1..)
|
||||
.map(|remaining_data| {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: make(dst, src),
|
||||
cycles: 8,
|
||||
},
|
||||
// guaranteed to succeed given we found the opcode
|
||||
remaining_data,
|
||||
)
|
||||
})
|
||||
.ok_or(Error::NoData)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue