Add JP HL instruction
parent
49f2e53e4e
commit
cd05183bb3
|
@ -6,6 +6,7 @@ pub enum ControlFlowInstruction {
|
|||
JumpToImmediate {
|
||||
addr: u16,
|
||||
},
|
||||
JumpToAddressInHL,
|
||||
Call {
|
||||
addr: u16,
|
||||
},
|
||||
|
|
|
@ -24,11 +24,11 @@ impl OpcodeParser for Parser {
|
|||
}
|
||||
|
||||
fn parse_unconditional_control_operation(data: &View) -> ParseResult {
|
||||
parse_unconditional_immediate_based_control_flow_operation(data)
|
||||
parse_unconditional_parameterized_control_flow_operation(data)
|
||||
.or_parse(parse_restart_instruction)
|
||||
}
|
||||
|
||||
fn parse_unconditional_immediate_based_control_flow_operation(data: &View) -> ParseResult {
|
||||
fn parse_unconditional_parameterized_control_flow_operation(data: &View) -> ParseResult {
|
||||
let opcode = parse::get_opcode_from_data(data);
|
||||
match opcode {
|
||||
0xC3 => Ok(build_immediate_parameterized_control_flow_data(
|
||||
|
@ -39,6 +39,10 @@ fn parse_unconditional_immediate_based_control_flow_operation(data: &View) -> Pa
|
|||
data,
|
||||
|addr| ControlFlowInstruction::Call { addr },
|
||||
)),
|
||||
0xE9 => Ok((
|
||||
Instruction::ControlFlow(ControlFlowInstruction::JumpToAddressInHL),
|
||||
1,
|
||||
)),
|
||||
_ => Err(parse::Error::UnknownOpcode(opcode)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,19 +6,24 @@ impl Run for ControlFlowInstruction {
|
|||
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, super::Error> {
|
||||
match *self {
|
||||
Self::JumpToImmediate { addr } => {
|
||||
processor
|
||||
.registers
|
||||
.set_single_16bit_register(register::SingleSixteenBit::ProgramCounter, addr);
|
||||
jump_to(processor, addr);
|
||||
|
||||
Ok(Cycles(16))
|
||||
}
|
||||
|
||||
Self::JumpToAddressInHL => {
|
||||
let addr = processor
|
||||
.registers
|
||||
.get_combined_register(register::Combined::HL);
|
||||
|
||||
jump_to(processor, addr);
|
||||
|
||||
Ok(Cycles(4))
|
||||
}
|
||||
|
||||
Self::JumpToImmediateIfFlagMatches { flag, value, addr } => {
|
||||
if processor.registers.get_flag_bit(flag) == value {
|
||||
processor.registers.set_single_16bit_register(
|
||||
register::SingleSixteenBit::ProgramCounter,
|
||||
addr,
|
||||
);
|
||||
jump_to(processor, addr);
|
||||
Ok(Cycles(16))
|
||||
} else {
|
||||
Ok(Cycles(12))
|
||||
|
@ -65,9 +70,13 @@ fn do_call(processor: &mut Processor, to_addr: u16) -> Result<(), super::Error>
|
|||
// We know the call instruction to be 3 bytes. A bit of a hack, but eh.
|
||||
processor.push_16bit_value_to_stack(current_pc.wrapping_add(3))?;
|
||||
|
||||
processor
|
||||
.registers
|
||||
.set_single_16bit_register(register::SingleSixteenBit::ProgramCounter, to_addr);
|
||||
jump_to(processor, to_addr);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn jump_to(processor: &mut Processor, to_addr: u16) {
|
||||
processor
|
||||
.registers
|
||||
.set_single_16bit_register(register::SingleSixteenBit::ProgramCounter, to_addr);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use ferris_boi::{
|
||||
cpu::{instructions::Instruction, Processor},
|
||||
register::Flag,
|
||||
register::{self, Flag},
|
||||
};
|
||||
use test_case::test_case;
|
||||
|
||||
|
@ -18,6 +18,23 @@ fn test_can_jump_to_immediate() {
|
|||
assert_eq!(0x1337, processor.registers.program_counter);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_can_jump_to_address_in_hl() {
|
||||
let mut processor = Processor::default();
|
||||
processor
|
||||
.registers
|
||||
.set_combined_register(register::Combined::HL, 0x1337);
|
||||
|
||||
let data = [0xE9, 0x06];
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x06]);
|
||||
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0x1337, processor.registers.program_counter);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call_adjusts_program_counter_to_given_value() {
|
||||
let mut processor = Processor::default();
|
||||
|
|
Loading…
Reference in New Issue