Implement jump immediate instruction
parent
710e293a0e
commit
409e46eea9
|
@ -34,6 +34,7 @@ impl Processor {
|
|||
parse::next_instruction(&memory_view).expect("invalid instruction");
|
||||
|
||||
let interrupt_enable_pending_already = self.interrupt_enable_pending;
|
||||
let pc_before_instruction_run = self.registers.program_counter;
|
||||
self.run_instruction(instruction);
|
||||
|
||||
// EI does not work until after the following instruction, so we check after running an instruction if
|
||||
|
@ -43,8 +44,12 @@ impl Processor {
|
|||
self.registers.enable_interrupts();
|
||||
}
|
||||
|
||||
let next_pc = pc.wrapping_add(bytes_read);
|
||||
self.registers.program_counter = next_pc;
|
||||
if pc_before_instruction_run == self.registers.program_counter {
|
||||
// The program counter should be advanced *ONLY* if the instruction did not modify the PC register
|
||||
|
||||
let next_pc = pc.wrapping_add(bytes_read);
|
||||
self.registers.program_counter = next_pc;
|
||||
}
|
||||
}
|
||||
|
||||
/// Run a single instruction on the CPU.
|
||||
|
|
|
@ -6,6 +6,7 @@ use super::parse::{self, Error};
|
|||
|
||||
pub mod arith16;
|
||||
pub mod arith8;
|
||||
pub mod control;
|
||||
pub mod load16;
|
||||
pub mod load8;
|
||||
pub mod misc;
|
||||
|
@ -19,6 +20,7 @@ pub enum Instruction {
|
|||
EightBitArithmetic(arith8::EightBitArithmeticInstruction),
|
||||
StackPointerAdjust(arith8::AdjustStackPointerInstruction),
|
||||
SixteenBitArithmetic(arith16::SixteenBitArithmeticInstruction),
|
||||
ControlFlow(control::ControlFlowInstruction),
|
||||
Misc(misc::MiscInstruction),
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#[allow(clippy::module_name_repetitions)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ControlFlowInstruction {
|
||||
JumpToImmediate { addr: u16 },
|
||||
}
|
|
@ -7,6 +7,7 @@ use thiserror::Error;
|
|||
|
||||
mod arith16;
|
||||
mod arith8;
|
||||
mod control;
|
||||
mod load16;
|
||||
mod load8;
|
||||
mod misc;
|
||||
|
@ -45,6 +46,7 @@ pub fn next_instruction(data: &View) -> ParseResult {
|
|||
load16::stack::Parser::parse_opcode,
|
||||
arith8::Parser::parse_opcode,
|
||||
arith16::Parser::parse_opcode,
|
||||
control::Parser::parse_opcode,
|
||||
misc::Parser::parse_opcode,
|
||||
];
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::{control::ControlFlowInstruction, Instruction},
|
||||
parse,
|
||||
},
|
||||
memory::{GetViewTuple, View},
|
||||
};
|
||||
|
||||
use super::{OpcodeParser, ParseOutput, ParseResult};
|
||||
|
||||
pub struct Parser;
|
||||
|
||||
impl OpcodeParser for Parser {
|
||||
fn parse_opcode(data: &View) -> ParseResult {
|
||||
let opcode = parse::get_opcode_from_data(data);
|
||||
match opcode {
|
||||
0xC3 => Ok(build_jump_to_immediate_data(data)),
|
||||
_ => Err(parse::Error::UnknownOpcode(opcode)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_jump_to_immediate_data(data: &View) -> ParseOutput {
|
||||
let (_opcode, lower_bytes, upper_bytes) = data.get_tuple();
|
||||
|
||||
// manual doesn't state this should be LE, but some inspection of games and googling
|
||||
// indicates it should be.
|
||||
let addr = u16::from_le_bytes([lower_bytes, upper_bytes]);
|
||||
(
|
||||
Instruction::ControlFlow(ControlFlowInstruction::JumpToImmediate { addr }),
|
||||
3,
|
||||
)
|
||||
}
|
|
@ -7,6 +7,7 @@ use thiserror::Error;
|
|||
mod arith16;
|
||||
mod arith8;
|
||||
mod arithutil;
|
||||
mod control;
|
||||
mod load16;
|
||||
mod load8;
|
||||
mod misc;
|
||||
|
@ -48,6 +49,7 @@ pub fn run_instruction(
|
|||
Instruction::EightBitArithmetic(arith_instruction) => arith_instruction.run_on(processor),
|
||||
Instruction::StackPointerAdjust(adjust_instruction) => adjust_instruction.run_on(processor),
|
||||
Instruction::SixteenBitArithmetic(arith_instruction) => arith_instruction.run_on(processor),
|
||||
Instruction::ControlFlow(control_instruction) => control_instruction.run_on(processor),
|
||||
Instruction::Misc(instruction) => instruction.run_on(processor),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
use crate::cpu::{instructions::control::ControlFlowInstruction, register, Processor};
|
||||
|
||||
use super::{Cycles, Run};
|
||||
|
||||
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);
|
||||
|
||||
Ok(Cycles(16))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
use ferris_boi::cpu::{instructions::Instruction, Processor};
|
||||
|
||||
#[test]
|
||||
fn test_can_jump_to_immediate() {
|
||||
let mut processor = Processor::default();
|
||||
|
||||
let data = [0xC3, 0x37, 0x13, 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);
|
||||
}
|
|
@ -73,6 +73,7 @@ fn test_jsmoo_test(filename: &str) {
|
|||
processor.registers.l, test_case.r#final.l,
|
||||
"register l value was incorrect"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
processor.registers.program_counter, test_case.r#final.pc,
|
||||
"program counter was incorrect"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod arith16;
|
||||
mod arith8;
|
||||
mod control;
|
||||
mod jsmoo;
|
||||
mod load16;
|
||||
mod load8;
|
||||
|
|
Loading…
Reference in New Issue