Implement jump immediate instruction

old-bit-manip
Nick Krichevsky 2023-11-21 14:55:40 -05:00
parent 710e293a0e
commit 409e46eea9
11 changed files with 85 additions and 2 deletions

View File

@ -34,6 +34,7 @@ impl Processor {
parse::next_instruction(&memory_view).expect("invalid instruction"); parse::next_instruction(&memory_view).expect("invalid instruction");
let interrupt_enable_pending_already = self.interrupt_enable_pending; let interrupt_enable_pending_already = self.interrupt_enable_pending;
let pc_before_instruction_run = self.registers.program_counter;
self.run_instruction(instruction); self.run_instruction(instruction);
// EI does not work until after the following instruction, so we check after running an instruction if // 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(); self.registers.enable_interrupts();
} }
let next_pc = pc.wrapping_add(bytes_read); if pc_before_instruction_run == self.registers.program_counter {
self.registers.program_counter = next_pc; // 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. /// Run a single instruction on the CPU.

View File

@ -6,6 +6,7 @@ use super::parse::{self, Error};
pub mod arith16; pub mod arith16;
pub mod arith8; pub mod arith8;
pub mod control;
pub mod load16; pub mod load16;
pub mod load8; pub mod load8;
pub mod misc; pub mod misc;
@ -19,6 +20,7 @@ pub enum Instruction {
EightBitArithmetic(arith8::EightBitArithmeticInstruction), EightBitArithmetic(arith8::EightBitArithmeticInstruction),
StackPointerAdjust(arith8::AdjustStackPointerInstruction), StackPointerAdjust(arith8::AdjustStackPointerInstruction),
SixteenBitArithmetic(arith16::SixteenBitArithmeticInstruction), SixteenBitArithmetic(arith16::SixteenBitArithmeticInstruction),
ControlFlow(control::ControlFlowInstruction),
Misc(misc::MiscInstruction), Misc(misc::MiscInstruction),
} }

View File

@ -0,0 +1,5 @@
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone, Copy)]
pub enum ControlFlowInstruction {
JumpToImmediate { addr: u16 },
}

View File

@ -7,6 +7,7 @@ use thiserror::Error;
mod arith16; mod arith16;
mod arith8; mod arith8;
mod control;
mod load16; mod load16;
mod load8; mod load8;
mod misc; mod misc;
@ -45,6 +46,7 @@ pub fn next_instruction(data: &View) -> ParseResult {
load16::stack::Parser::parse_opcode, load16::stack::Parser::parse_opcode,
arith8::Parser::parse_opcode, arith8::Parser::parse_opcode,
arith16::Parser::parse_opcode, arith16::Parser::parse_opcode,
control::Parser::parse_opcode,
misc::Parser::parse_opcode, misc::Parser::parse_opcode,
]; ];

33
src/cpu/parse/control.rs Normal file
View File

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

View File

@ -7,6 +7,7 @@ use thiserror::Error;
mod arith16; mod arith16;
mod arith8; mod arith8;
mod arithutil; mod arithutil;
mod control;
mod load16; mod load16;
mod load8; mod load8;
mod misc; mod misc;
@ -48,6 +49,7 @@ pub fn run_instruction(
Instruction::EightBitArithmetic(arith_instruction) => arith_instruction.run_on(processor), Instruction::EightBitArithmetic(arith_instruction) => arith_instruction.run_on(processor),
Instruction::StackPointerAdjust(adjust_instruction) => adjust_instruction.run_on(processor), Instruction::StackPointerAdjust(adjust_instruction) => adjust_instruction.run_on(processor),
Instruction::SixteenBitArithmetic(arith_instruction) => arith_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), Instruction::Misc(instruction) => instruction.run_on(processor),
} }
} }

17
src/cpu/run/control.rs Normal file
View File

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

15
tests/cpu/control.rs Normal file
View File

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

View File

@ -73,6 +73,7 @@ fn test_jsmoo_test(filename: &str) {
processor.registers.l, test_case.r#final.l, processor.registers.l, test_case.r#final.l,
"register l value was incorrect" "register l value was incorrect"
); );
assert_eq!( assert_eq!(
processor.registers.program_counter, test_case.r#final.pc, processor.registers.program_counter, test_case.r#final.pc,
"program counter was incorrect" "program counter was incorrect"

View File

@ -1,5 +1,6 @@
mod arith16; mod arith16;
mod arith8; mod arith8;
mod control;
mod jsmoo; mod jsmoo;
mod load16; mod load16;
mod load8; mod load8;