Add JP HL instruction

old-bit-manip
Nick Krichevsky 2023-11-21 23:20:40 -05:00
parent 49f2e53e4e
commit cd05183bb3
5 changed files with 44 additions and 13 deletions

View File

@ -6,6 +6,7 @@ pub enum ControlFlowInstruction {
JumpToImmediate {
addr: u16,
},
JumpToAddressInHL,
Call {
addr: u16,
},

View File

@ -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)),
}
}

View File

@ -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);
}

View File

@ -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();