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 { JumpToImmediate {
addr: u16, addr: u16,
}, },
JumpToAddressInHL,
Call { Call {
addr: u16, addr: u16,
}, },

View File

@ -24,11 +24,11 @@ impl OpcodeParser for Parser {
} }
fn parse_unconditional_control_operation(data: &View) -> ParseResult { 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) .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); let opcode = parse::get_opcode_from_data(data);
match opcode { match opcode {
0xC3 => Ok(build_immediate_parameterized_control_flow_data( 0xC3 => Ok(build_immediate_parameterized_control_flow_data(
@ -39,6 +39,10 @@ fn parse_unconditional_immediate_based_control_flow_operation(data: &View) -> Pa
data, data,
|addr| ControlFlowInstruction::Call { addr }, |addr| ControlFlowInstruction::Call { addr },
)), )),
0xE9 => Ok((
Instruction::ControlFlow(ControlFlowInstruction::JumpToAddressInHL),
1,
)),
_ => Err(parse::Error::UnknownOpcode(opcode)), _ => 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> { fn run_on(&self, processor: &mut Processor) -> Result<Cycles, super::Error> {
match *self { match *self {
Self::JumpToImmediate { addr } => { Self::JumpToImmediate { addr } => {
processor jump_to(processor, addr);
.registers
.set_single_16bit_register(register::SingleSixteenBit::ProgramCounter, addr);
Ok(Cycles(16)) 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 } => { Self::JumpToImmediateIfFlagMatches { flag, value, addr } => {
if processor.registers.get_flag_bit(flag) == value { if processor.registers.get_flag_bit(flag) == value {
processor.registers.set_single_16bit_register( jump_to(processor, addr);
register::SingleSixteenBit::ProgramCounter,
addr,
);
Ok(Cycles(16)) Ok(Cycles(16))
} else { } else {
Ok(Cycles(12)) 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. // 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.push_16bit_value_to_stack(current_pc.wrapping_add(3))?;
processor jump_to(processor, to_addr);
.registers
.set_single_16bit_register(register::SingleSixteenBit::ProgramCounter, to_addr);
Ok(()) 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::{ use ferris_boi::{
cpu::{instructions::Instruction, Processor}, cpu::{instructions::Instruction, Processor},
register::Flag, register::{self, Flag},
}; };
use test_case::test_case; use test_case::test_case;
@ -18,6 +18,23 @@ fn test_can_jump_to_immediate() {
assert_eq!(0x1337, processor.registers.program_counter); 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] #[test]
fn test_call_adjusts_program_counter_to_given_value() { fn test_call_adjusts_program_counter_to_given_value() {
let mut processor = Processor::default(); let mut processor = Processor::default();