Add ability to load from i/o registers relative to immediate
This commit is contained in:
parent
75235ad5e0
commit
e2365aec7e
40
src/run.rs
40
src/run.rs
|
@ -107,6 +107,16 @@ impl Processor {
|
||||||
|
|
||||||
self.registers.set_combined_register(dst, dst_address + 1);
|
self.registers.set_combined_register(dst, dst_address + 1);
|
||||||
}
|
}
|
||||||
|
Instruction::LDToMemoryRelativeToIORegisterStartByImmediate { src, offset } => {
|
||||||
|
let dst_address = memory::IO_REGISTER_START_ADDRESS + usize::from(offset);
|
||||||
|
let load_res = self.load_from_register_to_address(dst_address, src);
|
||||||
|
assert_ok!(load_res);
|
||||||
|
}
|
||||||
|
Instruction::LDFromMemoryRelativeToIORegisterStartByImmediate { dst, offset } => {
|
||||||
|
let src_address = memory::IO_REGISTER_START_ADDRESS + usize::from(offset);
|
||||||
|
let load_res = self.load_from_address_to_register(dst, src_address);
|
||||||
|
assert_ok!(load_res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.num_cycles += u64::from(instruction.cycles);
|
self.num_cycles += u64::from(instruction.cycles);
|
||||||
|
@ -464,4 +474,34 @@ mod tests {
|
||||||
.get_combined_register(register::Combined::HL)
|
.get_combined_register(register::Combined::HL)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_to_io_register_zone_by_immediate() {
|
||||||
|
let mut processor = Processor::default();
|
||||||
|
processor.registers.a = 0xAF;
|
||||||
|
|
||||||
|
let data = [0xE0, 0x05, 0x06];
|
||||||
|
let (ins, extra_data) =
|
||||||
|
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||||
|
|
||||||
|
assert_eq!(extra_data, &[0x06]);
|
||||||
|
processor.run(&ins);
|
||||||
|
|
||||||
|
assert_eq!(Some(0xAF), processor.memory.get(0xFF05));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_from_io_register_zone_by_immediate() {
|
||||||
|
let mut processor = Processor::default();
|
||||||
|
processor.memory.set(0xFF05, 0xAF);
|
||||||
|
|
||||||
|
let data = [0xF0, 0x05, 0x06];
|
||||||
|
let (ins, extra_data) =
|
||||||
|
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||||
|
|
||||||
|
assert_eq!(extra_data, &[0x06]);
|
||||||
|
processor.run(&ins);
|
||||||
|
|
||||||
|
assert_eq!(0xAF, processor.registers.a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,16 @@ pub enum Instruction {
|
||||||
// A register whose value will be used to get the address relative to FF00
|
// A register whose value will be used to get the address relative to FF00
|
||||||
offset_register: register::Single,
|
offset_register: register::Single,
|
||||||
},
|
},
|
||||||
|
// 3.3.1.20
|
||||||
|
LDFromMemoryRelativeToIORegisterStartByImmediate {
|
||||||
|
dst: register::Single,
|
||||||
|
offset: u8,
|
||||||
|
},
|
||||||
|
// 3.3.1.19
|
||||||
|
LDToMemoryRelativeToIORegisterStartByImmediate {
|
||||||
|
offset: u8,
|
||||||
|
src: register::Single,
|
||||||
|
},
|
||||||
LDFromImmediateAddress {
|
LDFromImmediateAddress {
|
||||||
src_address: u16,
|
src_address: u16,
|
||||||
dst: register::Single,
|
dst: register::Single,
|
||||||
|
|
|
@ -68,6 +68,13 @@ fn parse_load_from_address_to_register(data: &[u8]) -> ParseResult {
|
||||||
register::Single::A,
|
register::Single::A,
|
||||||
data,
|
data,
|
||||||
),
|
),
|
||||||
|
0xF0 => make_ld_from_memory_relative_to_io_register_start_by_immediate(
|
||||||
|
register::Single::A,
|
||||||
|
data,
|
||||||
|
),
|
||||||
|
0xE0 => {
|
||||||
|
make_ld_to_memory_relative_to_io_register_start_by_immediate(register::Single::A, data)
|
||||||
|
}
|
||||||
|
|
||||||
_ => Err(Error::UnknownOpcode(opcode)),
|
_ => Err(Error::UnknownOpcode(opcode)),
|
||||||
}
|
}
|
||||||
|
@ -227,6 +234,46 @@ fn make_ld_to_memory_relative_to_io_register_start(
|
||||||
.ok_or(Error::NoData)
|
.ok_or(Error::NoData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_ld_to_memory_relative_to_io_register_start_by_immediate(
|
||||||
|
src: register::Single,
|
||||||
|
data: &[u8],
|
||||||
|
) -> ParseResult {
|
||||||
|
let opcode = parse::get_opcode_from_data(data)?;
|
||||||
|
let value = data.get(1).ok_or(Error::NotEnoughArgs(opcode))?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
RunnableInstruction {
|
||||||
|
instruction: Instruction::LDToMemoryRelativeToIORegisterStartByImmediate {
|
||||||
|
src,
|
||||||
|
offset: *value,
|
||||||
|
},
|
||||||
|
// guaranteed to succeed given we got the value
|
||||||
|
cycles: 12,
|
||||||
|
},
|
||||||
|
&data[2..],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_ld_from_memory_relative_to_io_register_start_by_immediate(
|
||||||
|
dst: register::Single,
|
||||||
|
data: &[u8],
|
||||||
|
) -> ParseResult {
|
||||||
|
let opcode = parse::get_opcode_from_data(data)?;
|
||||||
|
let value = data.get(1).ok_or(Error::NotEnoughArgs(opcode))?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
RunnableInstruction {
|
||||||
|
instruction: Instruction::LDFromMemoryRelativeToIORegisterStartByImmediate {
|
||||||
|
offset: *value,
|
||||||
|
dst,
|
||||||
|
},
|
||||||
|
cycles: 12,
|
||||||
|
},
|
||||||
|
// guaranteed to succeed given we got the value
|
||||||
|
&data[2..],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn make_ld_to_address_then_do_arithmetic<
|
fn make_ld_to_address_then_do_arithmetic<
|
||||||
F: Fn(register::Combined, register::Single) -> Instruction,
|
F: Fn(register::Combined, register::Single) -> Instruction,
|
||||||
>(
|
>(
|
||||||
|
|
Loading…
Reference in a new issue