Add support for loading to A from immediate address

jsmoo
Nick Krichevsky 2022-04-05 00:21:58 -04:00
parent cb535e24c3
commit 28132d60fa
1 changed files with 92 additions and 13 deletions

View File

@ -26,12 +26,16 @@ pub enum Instruction {
src: register::Single,
},
// 3.3.1.2/3.3.1.3, only the loading from (nn) instructions
LDFromAddress {
LDFromRegisterAddress {
// src, unlike some of the other instructions, is a 16bit combined register that will be
// dereferenced to get the value to place into the dst register
src: register::Combined,
dst: register::Single,
},
LDFromImmediateAddress {
src_address: u16,
dst: register::Single,
},
// 3.3.1.2, only the loading to (hl) instructions
LDToHLAddress {
src: register::Single,
@ -70,49 +74,77 @@ impl RunnableInstruction {
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 => Self::make_ld_from_address(register::Combined::HL, register::Single::A, data),
0x7E => Self::make_ld_from_register_address(
register::Combined::HL,
register::Single::A,
data,
),
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 => Self::make_ld_from_address(register::Combined::HL, register::Single::B, data),
0x46 => Self::make_ld_from_register_address(
register::Combined::HL,
register::Single::B,
data,
),
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 => Self::make_ld_from_address(register::Combined::HL, register::Single::C, data),
0x4E => Self::make_ld_from_register_address(
register::Combined::HL,
register::Single::C,
data,
),
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 => Self::make_ld_from_address(register::Combined::HL, register::Single::D, data),
0x56 => Self::make_ld_from_register_address(
register::Combined::HL,
register::Single::D,
data,
),
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 => Self::make_ld_from_address(register::Combined::HL, register::Single::E, data),
0x5E => Self::make_ld_from_register_address(
register::Combined::HL,
register::Single::E,
data,
),
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 => Self::make_ld_from_address(register::Combined::HL, register::Single::H, data),
0x66 => Self::make_ld_from_register_address(
register::Combined::HL,
register::Single::H,
data,
),
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),
0x6E => Self::make_ld_from_address(register::Combined::HL, register::Single::L, data),
0x6E => Self::make_ld_from_register_address(
register::Combined::HL,
register::Single::L,
data,
),
0x70 => Self::make_ld_to_hl_address(register::Single::B, data),
0x71 => Self::make_ld_to_hl_address(register::Single::C, data),
0x72 => Self::make_ld_to_hl_address(register::Single::D, data),
@ -121,8 +153,17 @@ impl RunnableInstruction {
0x75 => Self::make_ld_to_hl_address(register::Single::L, data),
0x36 => Self::make_ld_n_to_hl_address(data),
0x0A => Self::make_ld_from_address(register::Combined::BC, register::Single::A, data),
0x1A => Self::make_ld_from_address(register::Combined::DE, register::Single::A, data),
0xFA => Self::make_ld_from_immediate_address(register::Single::A, data),
0x0A => Self::make_ld_from_register_address(
register::Combined::BC,
register::Single::A,
data,
),
0x1A => Self::make_ld_from_register_address(
register::Combined::DE,
register::Single::A,
data,
),
_ => panic!("invalid opcode {opcode:0x}"),
}
@ -155,20 +196,35 @@ impl RunnableInstruction {
)
}
fn make_ld_from_address(
fn make_ld_from_register_address(
src: register::Combined,
dst: register::Single,
data: &[u8],
) -> (RunnableInstruction, &[u8]) {
(
RunnableInstruction {
instruction: Instruction::LDFromAddress { src, dst },
instruction: Instruction::LDFromRegisterAddress { src, dst },
cycles: 8,
},
&data[1..],
)
}
fn make_ld_from_immediate_address(
dst: register::Single,
data: &[u8],
) -> (RunnableInstruction, &[u8]) {
// The manual states that the LSB of the address is specified first (i.e. little endian)
let src_address = u16::from_le_bytes([data[0], data[1]]);
(
RunnableInstruction {
instruction: Instruction::LDFromImmediateAddress { src_address, dst },
cycles: 16,
},
&data[3..],
)
}
fn make_ld_to_hl_address(src: register::Single, data: &[u8]) -> (RunnableInstruction, &[u8]) {
(
RunnableInstruction {
@ -202,7 +258,7 @@ impl Processor {
self.registers.set_single_register(dst, src_value);
}
Instruction::LDFromAddress { src, dst } => {
Instruction::LDFromRegisterAddress { src, dst } => {
let src_address = self.registers.get_combined_register(src);
let memory_value = self.memory.get(src_address.into());
if memory_value.is_none() {
@ -213,6 +269,16 @@ impl Processor {
.set_single_register(dst, memory_value.unwrap());
}
Instruction::LDFromImmediateAddress { src_address, dst } => {
let memory_value = self.memory.get(src_address.into());
if memory_value.is_none() {
panic!("invalid address immediate: {src_address}")
}
self.registers
.set_single_register(dst, memory_value.unwrap());
}
Instruction::LDToHLAddress { src } => {
let value = self.registers.get_single_register(src);
let dst_address = self.registers.get_combined_register(register::Combined::HL);
@ -403,4 +469,17 @@ mod tests {
processor.run(&ins);
assert_eq!(Some(0x1D), processor.memory.get(0xCCDE));
}
#[test]
fn test_load_from_immediate_address() {
let mut processor = Processor::default();
processor.memory.set(0xCCDE, 105);
let data = [0xFA, 0xDE, 0xCC, 0x00];
let (ins, extra_data) = RunnableInstruction::from_data(&data);
assert_eq!(extra_data, &[0x00]);
processor.run(&ins);
assert_eq!(Some(105), processor.memory.get(0xCCDE));
}
}