Add support for loading to A from immediate address
parent
cb535e24c3
commit
28132d60fa
105
src/run.rs
105
src/run.rs
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue