Remove RunnableInstruction, encode cycles as a result of runtime

This is necessary for certain instructions, since they can take a different number of cycles
old-bit-manip
Nick Krichevsky 2023-11-20 14:25:07 -05:00
parent f9cdccb5fd
commit b5117e7cf9
25 changed files with 420 additions and 631 deletions

View File

@ -1,4 +1,4 @@
use instructions::RunnableInstruction;
use instructions::Instruction;
use run::Error;
use crate::{
@ -32,7 +32,7 @@ impl Processor {
let (instruction, bytes_read) =
parse::next_instruction(&memory_view).expect("invalid instruction");
self.run_instruction(&instruction);
self.run_instruction(instruction);
let (next_pc, _carry) = pc.overflowing_add(bytes_read);
self.registers.program_counter = next_pc;
@ -42,13 +42,13 @@ impl Processor {
///
/// # Panics
/// Panics if an internal error occurred within the CPU. These are always bugs.
pub fn run_instruction(&mut self, instruction: &RunnableInstruction) {
let run_res = run::run_instruction(self, instruction.instruction);
pub fn run_instruction(&mut self, instruction: Instruction) {
let run_res = run::run_instruction(self, instruction);
if let Err(err) = run_res {
panic!("Fatal CPU error occured: {err}")
}
self.num_cycles += u128::from(instruction.cycles);
self.num_cycles += u128::from(run_res.unwrap().0);
}
fn load_from_register_to_register_address(

View File

@ -22,14 +22,7 @@ pub enum Instruction {
Misc(misc::MiscInstruction),
}
/// `RunnableInstruction` is an instruction that can run on the processor, and has any metadata needed to do so
#[derive(Debug, Clone)]
pub struct RunnableInstruction {
pub(super) instruction: Instruction,
pub(super) cycles: u8,
}
impl RunnableInstruction {
impl Instruction {
/// `from_data` will produce an instruction from the given data and return the data after
/// processing that operation.
///
@ -37,7 +30,7 @@ impl RunnableInstruction {
///
/// # Errors
/// Returns an error if the instruction couldn't be parsed.
pub fn from_data(data: &[u8]) -> Result<(RunnableInstruction, &[u8]), Error> {
pub fn from_data(data: &[u8]) -> Result<(Self, &[u8]), Error> {
parse::next_instruction(&View::new_from_data(data, 0))
.map(|(ins, offset)| (ins, &data[offset.into()..]))
}

View File

@ -2,7 +2,7 @@
use crate::memory::View;
use super::instructions::RunnableInstruction;
use super::instructions::Instruction;
use thiserror::Error;
mod arith16;
@ -22,7 +22,7 @@ pub enum Error {
}
/// `ParseResult` is the result of a Parse operation, which includes the parsed instruction and the number of bytes read.
pub(super) type ParseOutput = (RunnableInstruction, u16);
pub(super) type ParseOutput = (Instruction, u16);
pub(super) type ParseResult = Result<ParseOutput, Error>;
/// `OpcodeParser` takes input data, parses out an opcode (and its associated arguments) if it can, and returns

View File

@ -1,7 +1,7 @@
use crate::{
cpu::{
instructions::arith16::SixteenBitArithmeticInstruction,
instructions::Instruction,
instructions::{arith16::SixteenBitArithmeticInstruction, RunnableInstruction},
parse::{self, Error, OpcodeParser, ParseResult},
register::{Combined, SingleSixteenBit, SixteenBit},
},
@ -49,36 +49,27 @@ impl OpcodeParser for Parser {
fn build_add_hl_to_register_data(operand_register: SixteenBit) -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::SixteenBitArithmetic(
SixteenBitArithmeticInstruction::AddRegisterToHL { operand_register },
),
cycles: 8,
},
Instruction::SixteenBitArithmetic(SixteenBitArithmeticInstruction::AddRegisterToHL {
operand_register,
}),
1,
)
}
fn build_inc_register_data(operand_register: SixteenBit) -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::SixteenBitArithmetic(
SixteenBitArithmeticInstruction::IncrementRegister { operand_register },
),
cycles: 8,
},
Instruction::SixteenBitArithmetic(SixteenBitArithmeticInstruction::IncrementRegister {
operand_register,
}),
1,
)
}
fn build_dec_register_data(operand_register: SixteenBit) -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::SixteenBitArithmetic(
SixteenBitArithmeticInstruction::DecrementRegister { operand_register },
),
cycles: 8,
},
Instruction::SixteenBitArithmetic(SixteenBitArithmeticInstruction::DecrementRegister {
operand_register,
}),
1,
)
}

View File

@ -3,7 +3,7 @@ use crate::{
arith8::{
AdjustStackPointerInstruction, EightBitArithmeticInstruction, Operand, Operation,
},
Instruction, RunnableInstruction,
Instruction,
},
memory::{GetViewTuple, View},
register,
@ -35,28 +35,12 @@ fn parse_eight_bit_arithmetic_instruction(data: &View) -> super::ParseResult {
let operation = operation_for_opcode(opcode)?;
let operand = operand_for_opcode(opcode)?;
let parse_data = match (operation, operand) {
(_operation, OpcodeOperand::SingleRegister(register)) => {
let parse_data = match operand {
OpcodeOperand::SingleRegister(register) => {
build_instruction_between_register_and_a_data(operation, register)
}
(Operation::Inc | Operation::Dec, OpcodeOperand::HLAddressValue) => {
let (runnable_ins, bytes_read) =
build_instruction_between_hl_value_and_a_data(operation);
// This is an exception to the other arithmetic instructions
(
RunnableInstruction {
cycles: 12,
..runnable_ins
},
bytes_read,
)
}
(_operation, OpcodeOperand::HLAddressValue) => {
build_instruction_between_hl_value_and_a_data(operation)
}
(_operation, OpcodeOperand::Immediate) => {
build_instruction_between_immediate_and_a_data(operation, data)
}
OpcodeOperand::HLAddressValue => build_instruction_between_hl_value_and_a_data(operation),
OpcodeOperand::Immediate => build_instruction_between_immediate_and_a_data(operation, data),
};
Ok(parse_data)
@ -157,13 +141,7 @@ fn build_instruction_between_register_and_a_data(
operation,
};
(
RunnableInstruction {
instruction: Instruction::EightBitArithmetic(instruction),
cycles: 4,
},
1,
)
(Instruction::EightBitArithmetic(instruction), 1)
}
fn build_instruction_between_hl_value_and_a_data(operation: Operation) -> ParseOutput {
@ -172,13 +150,7 @@ fn build_instruction_between_hl_value_and_a_data(operation: Operation) -> ParseO
operation,
};
(
RunnableInstruction {
instruction: Instruction::EightBitArithmetic(instruction),
cycles: 8,
},
1,
)
(Instruction::EightBitArithmetic(instruction), 1)
}
fn build_instruction_between_immediate_and_a_data(
@ -192,13 +164,7 @@ fn build_instruction_between_immediate_and_a_data(
operation,
};
(
RunnableInstruction {
instruction: Instruction::EightBitArithmetic(instruction),
cycles: 8,
},
2,
)
(Instruction::EightBitArithmetic(instruction), 2)
}
fn build_stack_pointer_adjust_data(data: &View) -> ParseOutput {
@ -207,13 +173,7 @@ fn build_stack_pointer_adjust_data(data: &View) -> ParseOutput {
operand: i8::from_be_bytes([n]),
};
(
RunnableInstruction {
instruction: Instruction::StackPointerAdjust(instruction),
cycles: 16,
},
2,
)
(Instruction::StackPointerAdjust(instruction), 2)
}
#[cfg(test)]

View File

@ -1,7 +1,7 @@
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
use crate::cpu::parse::ParseOutput;
use crate::cpu::{
instructions::{Instruction, RunnableInstruction},
instructions::Instruction,
parse::{self, Error, OpcodeParser, ParseResult},
};
use crate::memory::{GetViewTuple, View};
@ -44,12 +44,10 @@ fn make_load_immediate_data(dst: register::SixteenBit, data: &View) -> ParseOutp
// indicates it should be.
let value = u16::from_le_bytes([lower_bytes, upper_bytes]);
(
RunnableInstruction {
instruction: Instruction::SixteenBitLoad(
SixteenBitLoadInstruction::LoadImmediateToRegister { value, dst },
),
cycles: 12,
},
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::LoadImmediateToRegister {
value,
dst,
}),
3,
)
}
@ -59,15 +57,10 @@ fn make_load_effective_address(dst: register::Combined, data: &View) -> ParseOut
let signed_value = i8::from_be_bytes([unsigned_value]);
(
RunnableInstruction {
instruction: Instruction::SixteenBitLoad(
SixteenBitLoadInstruction::LoadEffectiveAddress {
dst,
offset: signed_value,
},
),
cycles: 12,
},
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::LoadEffectiveAddress {
dst,
offset: signed_value,
}),
2,
)
}

View File

@ -1,5 +1,5 @@
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
use crate::cpu::instructions::{Instruction, RunnableInstruction};
use crate::cpu::instructions::Instruction;
use crate::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult};
use crate::memory::{GetViewTuple, View};
use crate::register;
@ -59,14 +59,10 @@ impl OpcodeParser for Parser {
fn make_stack_operation_data(operation: Operation, reg: register::Combined) -> ParseOutput {
let instruction = match operation {
Operation::Push => RunnableInstruction {
instruction: Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Push { src: reg }),
cycles: 16,
},
Operation::Pop => RunnableInstruction {
instruction: Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Pop { dst: reg }),
cycles: 12,
},
Operation::Push => {
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Push { src: reg })
}
Operation::Pop => Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Pop { dst: reg }),
};
(instruction, 1)
@ -77,12 +73,9 @@ fn make_load_sp_to_address_data(data: &View) -> ParseOutput {
let dst_address = u16::from_le_bytes([address_half1, address_half2]);
(
RunnableInstruction {
instruction: Instruction::SixteenBitLoad(
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address },
),
cycles: 20,
},
Instruction::SixteenBitLoad(
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address },
),
3,
)
}

View File

@ -1,10 +1,7 @@
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
use crate::cpu::instructions::Instruction;
use crate::cpu::parse::ParseOutput;
use crate::cpu::{
instructions::RunnableInstruction,
parse::{self, Error, OpcodeParser, ParseResult},
};
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
use crate::memory::View;
use crate::register;
@ -29,12 +26,7 @@ fn make_load_between_register_data(
src: register::SixteenBit,
) -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::SixteenBitLoad(
SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src },
),
cycles: 8,
},
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src }),
1,
)
}

View File

@ -1,10 +1,7 @@
use crate::cpu::instructions::load8::EightBitLoadInstruction;
use crate::cpu::instructions::Instruction;
use crate::cpu::parse::ParseOutput;
use crate::cpu::{
instructions::RunnableInstruction,
parse::{self, Error, OpcodeParser, ParseResult},
};
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
use crate::memory::{GetViewTuple, View};
use crate::register;
@ -34,16 +31,10 @@ fn make_load_immediate_data(register: register::SingleEightBit, data: &View) ->
let (_opcode, value) = data.get_tuple();
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(
EightBitLoadInstruction::LoadImmediateToRegister { register, value },
),
// TODO: I don't love that the cycles are in a parsing function,
// but ultimately I want the cycles to be as close to the opcode as possible
// so that it's easier to change. Maybe I can change this once I end up with
// more of the instructions complete
cycles: 8,
},
Instruction::EightBitLoad(EightBitLoadInstruction::LoadImmediateToRegister {
register,
value,
}),
2,
)
}

View File

@ -1,5 +1,5 @@
use crate::cpu::instructions::load8::EightBitLoadInstruction;
use crate::cpu::instructions::{Instruction, RunnableInstruction};
use crate::cpu::instructions::Instruction;
use crate::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult};
use crate::memory::{GetViewTuple, View};
use crate::register;
@ -186,12 +186,7 @@ fn make_load_from_register_address(
src: register::Combined,
) -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(
EightBitLoadInstruction::LoadFromRegisterAddress { src, dst },
),
cycles: 8,
},
Instruction::EightBitLoad(EightBitLoadInstruction::LoadFromRegisterAddress { src, dst }),
1,
)
}
@ -201,12 +196,7 @@ fn make_load_to_register_address(
src: register::SingleEightBit,
) -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(
EightBitLoadInstruction::LoadToRegisterAddress { src, dst },
),
cycles: 8,
},
Instruction::EightBitLoad(EightBitLoadInstruction::LoadToRegisterAddress { src, dst }),
1,
)
}
@ -217,12 +207,10 @@ fn make_load_from_immediate_address(dst: register::SingleEightBit, data: &View)
// The manual states that the LSB of the address is specified first (i.e. little endian)
let src_address = u16::from_le_bytes([lower_bytes, upper_bytes]);
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(
EightBitLoadInstruction::LoadFromImmediateAddress { src_address, dst },
),
cycles: 16,
},
Instruction::EightBitLoad(EightBitLoadInstruction::LoadFromImmediateAddress {
src_address,
dst,
}),
3,
)
}
@ -233,12 +221,10 @@ fn make_load_to_immediate_address(src: register::SingleEightBit, data: &View) ->
// The manual states that the LSB of the address is specified first (i.e. little endian)
let dst_address = u16::from_le_bytes([lower_bytes, upper_bytes]);
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(
EightBitLoadInstruction::LoadToImmediateAddress { src, dst_address },
),
cycles: 16,
},
Instruction::EightBitLoad(EightBitLoadInstruction::LoadToImmediateAddress {
src,
dst_address,
}),
3,
)
}
@ -246,12 +232,7 @@ fn make_load_to_immediate_address(src: register::SingleEightBit, data: &View) ->
fn make_load_n_to_hl_address(data: &View) -> ParseOutput {
let (_opcode, value) = data.get_tuple();
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(EightBitLoadInstruction::LoadnToHLAddress {
value,
}),
cycles: 12,
},
Instruction::EightBitLoad(EightBitLoadInstruction::LoadnToHLAddress { value }),
2,
)
}
@ -261,16 +242,12 @@ fn make_load_from_memory_relative_to_io_register_start(
dst: register::SingleEightBit,
) -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStart {
offset_register,
dst,
},
),
cycles: 8,
},
// guaranteed to succeed given we found the opcode
Instruction::EightBitLoad(
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStart {
offset_register,
dst,
},
),
1,
)
}
@ -280,15 +257,12 @@ fn make_load_to_memory_relative_to_io_register_start(
src: register::SingleEightBit,
) -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStart {
src,
offset_register,
},
),
cycles: 8,
},
Instruction::EightBitLoad(
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStart {
src,
offset_register,
},
),
// guaranteed to succeed given we found the opcode
1,
)
@ -301,16 +275,12 @@ fn make_load_to_memory_relative_to_io_register_start_by_immediate(
let (_opcode, offset) = data.get_tuple();
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
src,
offset,
},
),
// guaranteed to succeed given we got the value
cycles: 12,
},
Instruction::EightBitLoad(
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
src,
offset,
},
),
2,
)
}
@ -322,15 +292,12 @@ fn make_load_from_memory_relative_to_io_register_start_by_immediate(
let (_opcode, offset) = data.get_tuple();
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStartByImmediate {
offset,
dst,
},
),
cycles: 12,
},
Instruction::EightBitLoad(
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStartByImmediate {
offset,
dst,
},
),
2,
)
}
@ -364,11 +331,5 @@ fn make_load_from_address_and_do_arithmetic<
fn make_load_and_do_arithmetic<F: Fn() -> EightBitLoadInstruction>(make: F) -> ParseOutput {
let load_instruction = make();
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(load_instruction),
cycles: 8,
},
1,
)
(Instruction::EightBitLoad(load_instruction), 1)
}

View File

@ -1,10 +1,7 @@
use crate::cpu::instructions::load8::EightBitLoadInstruction;
use crate::cpu::instructions::Instruction;
use crate::cpu::parse::ParseOutput;
use crate::cpu::{
instructions::RunnableInstruction,
parse::{self, Error, OpcodeParser, ParseResult},
};
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
use crate::memory::View;
use crate::register;
@ -54,13 +51,7 @@ fn make_load_between_register_data(
src: register::SingleEightBit,
) -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::EightBitLoad(EightBitLoadInstruction::LoadBetweenRegisters {
dst,
src,
}),
cycles: 4,
},
Instruction::EightBitLoad(EightBitLoadInstruction::LoadBetweenRegisters { dst, src }),
1,
)
}

View File

@ -1,6 +1,6 @@
use super::{OpcodeParser, ParseOutput, ParseResult};
use crate::{
cpu::instructions::{misc::MiscInstruction, Instruction, RunnableInstruction},
cpu::instructions::{misc::MiscInstruction, Instruction},
memory::View,
};
@ -20,41 +20,20 @@ impl OpcodeParser for Parser {
}
fn build_set_carry_flag_data() -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::Misc(MiscInstruction::SetCarryFlag),
cycles: 4,
},
1,
)
(Instruction::Misc(MiscInstruction::SetCarryFlag), 1)
}
fn build_complement_carry_flag_data() -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::Misc(MiscInstruction::ComplementCarryFlag),
cycles: 4,
},
1,
)
(Instruction::Misc(MiscInstruction::ComplementCarryFlag), 1)
}
fn build_complement_a_register_data() -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::Misc(MiscInstruction::ComplementARegister),
cycles: 4,
},
1,
)
(Instruction::Misc(MiscInstruction::ComplementARegister), 1)
}
fn build_daa_data() -> ParseOutput {
(
RunnableInstruction {
instruction: Instruction::Misc(MiscInstruction::DecimalAdjustAccumulator),
cycles: 4,
},
Instruction::Misc(MiscInstruction::DecimalAdjustAccumulator),
1,
)
}

View File

@ -30,12 +30,18 @@ pub enum Error {
/// `Run` takes a single instruction and runs it on the given processor.
trait Run {
fn run_on(&self, processor: &mut Processor) -> Result<(), Error>;
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error>;
}
/// `Cycles` represents the number of cycles an operation took
pub struct Cycles(pub u8);
/// `run_instruction` will run the given instruction on the processor.
#[allow(clippy::module_name_repetitions)]
pub fn run_instruction(processor: &mut Processor, instruction: Instruction) -> Result<(), Error> {
pub fn run_instruction(
processor: &mut Processor,
instruction: Instruction,
) -> Result<Cycles, Error> {
match instruction {
Instruction::EightBitLoad(load_instruction) => load_instruction.run_on(processor),
Instruction::SixteenBitLoad(load_instruction) => load_instruction.run_on(processor),

View File

@ -1,9 +1,9 @@
use crate::{cpu::instructions::arith16::SixteenBitArithmeticInstruction, register};
use super::{arithutil::CarryingAdd, Run};
use super::{arithutil::CarryingAdd, Cycles, Run};
impl Run for SixteenBitArithmeticInstruction {
fn run_on(&self, processor: &mut crate::cpu::Processor) -> Result<(), super::Error> {
fn run_on(&self, processor: &mut crate::cpu::Processor) -> Result<Cycles, super::Error> {
match *self {
SixteenBitArithmeticInstruction::IncrementRegister { operand_register } => {
let register_value = processor.registers.get_16bit_register(operand_register);
@ -12,7 +12,7 @@ impl Run for SixteenBitArithmeticInstruction {
.registers
.set_16bit_register(operand_register, incremented_value);
Ok(())
Ok(Cycles(8))
}
SixteenBitArithmeticInstruction::DecrementRegister { operand_register } => {
@ -22,7 +22,7 @@ impl Run for SixteenBitArithmeticInstruction {
.registers
.set_16bit_register(operand_register, decremented_value);
Ok(())
Ok(Cycles(8))
}
SixteenBitArithmeticInstruction::AddRegisterToHL { operand_register } => {
@ -45,7 +45,7 @@ impl Run for SixteenBitArithmeticInstruction {
.registers
.set_flag_bit(register::Flag::Subtract, 0);
Ok(())
Ok(Cycles(8))
}
}
}

View File

@ -7,7 +7,7 @@ use crate::{
register,
};
use super::{arithutil::CarryingAdd, Run};
use super::{arithutil::CarryingAdd, Cycles, Run};
mod binary;
mod unary;
@ -26,7 +26,7 @@ struct OperationFlagOutput {
}
impl Run for EightBitArithmeticInstruction {
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
match self.operation {
Operation::Add => binary::run_add(processor, self.operand),
@ -52,7 +52,7 @@ impl Run for EightBitArithmeticInstruction {
}
impl Run for AdjustStackPointerInstruction {
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
let stack_pointer = processor
.registers
.get_single_16bit_register(register::SingleSixteenBit::StackPointer);
@ -72,7 +72,7 @@ impl Run for AdjustStackPointerInstruction {
},
);
Ok(())
Ok(Cycles(16))
}
}

View File

@ -3,7 +3,7 @@ use crate::{
instructions::arith8::Operand,
run::{
arithutil::{self, CarriedNumber, CarryingAdd, CarryingSub},
Error,
Cycles, Error,
},
Processor,
},
@ -12,11 +12,11 @@ use crate::{
use super::{OperationFlagOutput, OperationOutput};
pub fn run_add(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_add(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
run_operation(processor, operand, run_add_on_operands)
}
pub fn run_add_with_carry(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_add_with_carry(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
run_operation_with_carry(processor, operand, run_add_on_operands)
}
@ -32,11 +32,11 @@ where
}
}
pub fn run_sub(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_sub(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
run_operation(processor, operand, run_sub_on_operands)
}
pub fn run_sub_with_carry(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_sub_with_carry(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
run_operation_with_carry(processor, operand, run_sub_on_operands)
}
@ -51,20 +51,20 @@ where
}
}
pub fn run_compare(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_compare(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
let a_value = processor.registers.a;
// A compare is just a sub, preserving the A value, so we can just do a sub
// and restore the original value
run_sub(processor, operand)?;
let sub_cycles = run_sub(processor, operand)?;
processor
.registers
.set_single_8bit_register(register::SingleEightBit::A, a_value);
Ok(())
Ok(sub_cycles)
}
pub fn run_and(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_and(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
run_operation(processor, operand, |lhs, rhs| {
let total = lhs & rhs;
@ -80,7 +80,7 @@ pub fn run_and(processor: &mut Processor, operand: Operand) -> Result<(), Error>
})
}
pub fn run_or(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_or(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
run_operation(processor, operand, |lhs, rhs| {
let total = lhs | rhs;
@ -96,7 +96,7 @@ pub fn run_or(processor: &mut Processor, operand: Operand) -> Result<(), Error>
})
}
pub fn run_xor(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_xor(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
run_operation(processor, operand, |lhs, rhs| {
let total = lhs ^ rhs;
@ -112,28 +112,32 @@ pub fn run_xor(processor: &mut Processor, operand: Operand) -> Result<(), Error>
})
}
fn run_operation<F>(processor: &mut Processor, operand: Operand, operation: F) -> Result<(), Error>
fn run_operation<F>(
processor: &mut Processor,
operand: Operand,
operation: F,
) -> Result<Cycles, Error>
where
F: FnOnce(u8, u8) -> OperationOutput,
{
let operand_values = gather_operand_values(processor, operand)?;
run_operation_on_operands(processor, operand_values, operation);
Ok(())
Ok(cycles_for_operand(operand))
}
fn run_operation_with_carry<F>(
processor: &mut Processor,
operand: Operand,
operation: F,
) -> Result<(), Error>
) -> Result<Cycles, Error>
where
F: FnOnce(u8, CarriedNumber<u8>) -> OperationOutput,
{
let operand_values = gather_operands_with_carry(processor, operand)?;
run_operation_on_operands(processor, operand_values, operation);
Ok(())
Ok(cycles_for_operand(operand))
}
fn run_operation_on_operands<F, L, R>(processor: &mut Processor, (lhs, rhs): (L, R), operation: F)
@ -235,6 +239,14 @@ fn addition_flags(total: u8, half_carry: bool, carry: bool) -> OperationFlagOutp
}
}
fn cycles_for_operand(operand: Operand) -> Cycles {
match operand {
Operand::SingleRegister(_register) => Cycles(4),
Operand::HLAddressValue => Cycles(8),
Operand::Immediate(_val) => Cycles(8),
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -3,7 +3,7 @@ use crate::{
instructions::arith8::Operand,
run::{
arithutil::{CarryingAdd, CarryingSub},
Error,
Cycles, Error,
},
Processor,
},
@ -12,7 +12,7 @@ use crate::{
use super::{OperationFlagOutput, OperationOutput};
pub fn run_inc(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_inc(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
let current_carry_flag = processor.registers.get_flag_bit(register::Flag::Carry);
run_operation(processor, operand, |value| {
let (result, half_carry, _full_carry) = value.add_with_carry(1);
@ -29,7 +29,7 @@ pub fn run_inc(processor: &mut Processor, operand: Operand) -> Result<(), Error>
})
}
pub fn run_dec(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
pub fn run_dec(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
let current_carry_flag = processor.registers.get_flag_bit(register::Flag::Carry);
run_operation(processor, operand, |value| {
let (result, half_carry, _full_carry) = value.sub_with_carry(1);
@ -46,7 +46,11 @@ pub fn run_dec(processor: &mut Processor, operand: Operand) -> Result<(), Error>
})
}
fn run_operation<F>(processor: &mut Processor, operand: Operand, operation: F) -> Result<(), Error>
fn run_operation<F>(
processor: &mut Processor,
operand: Operand,
operation: F,
) -> Result<Cycles, Error>
where
F: Fn(u8) -> OperationOutput,
{
@ -56,7 +60,7 @@ where
store_output_value(processor, operand, output.value)?;
super::store_flags(processor, output.flags);
Ok(())
Ok(cycles_for_operand(operand))
}
fn gather_operand_value(processor: &mut Processor, operand: Operand) -> Result<u8, Error> {
@ -122,3 +126,11 @@ fn store_output_value(
Operand::Immediate(_) => unreachable!("cannot perform unary operation on an immediate"),
}
}
fn cycles_for_operand(operand: Operand) -> Cycles {
match operand {
Operand::SingleRegister(_register) => Cycles(4),
Operand::HLAddressValue => Cycles(12),
Operand::Immediate(_val) => unreachable!("Cannot perform unary on immediate"),
}
}

View File

@ -1,24 +1,24 @@
use super::arithutil::CarryingAdd;
use super::{Error, Run};
use super::{Cycles, Error, Run};
use crate::cpu::{instructions::load16::SixteenBitLoadInstruction, Processor};
use crate::{memory, register};
impl Run for SixteenBitLoadInstruction {
// TODO: Fix this
#[allow(clippy::too_many_lines)]
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
match *self {
SixteenBitLoadInstruction::LoadImmediateToRegister { dst, value } => {
processor.registers.set_16bit_register(dst, value);
Ok(())
Ok(Cycles(12))
}
SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src } => {
let value = processor.registers.get_16bit_register(src);
processor.registers.set_16bit_register(dst, value);
Ok(())
Ok(Cycles(8))
}
SixteenBitLoadInstruction::LoadEffectiveAddress { dst, offset } => {
@ -43,7 +43,7 @@ impl Run for SixteenBitLoadInstruction {
processor.registers.set_combined_register(dst, new_sp);
Ok(())
Ok(Cycles(12))
}
SixteenBitLoadInstruction::Push { src } => {
@ -74,7 +74,7 @@ impl Run for SixteenBitLoadInstruction {
current_sp - 2,
);
Ok(())
Ok(Cycles(16))
}
SixteenBitLoadInstruction::Pop { dst } => {
@ -112,7 +112,7 @@ impl Run for SixteenBitLoadInstruction {
current_sp + 2,
);
Ok(())
Ok(Cycles(12))
}
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address } => {
let current_sp = processor
@ -126,7 +126,7 @@ impl Run for SixteenBitLoadInstruction {
));
match memory_res {
Ok(_) => Ok(()),
Ok(_) => Ok(Cycles(20)),
Err(memory::Error::GetInvalidAddress(bad_addr)) => {
Err(Error::InvalidImmediateAddress(bad_addr))
}

View File

@ -1,4 +1,4 @@
use super::{Error, Run};
use super::{Cycles, Error, Run};
use crate::{
cpu::{instructions::load8::EightBitLoadInstruction, Processor},
memory, register,
@ -7,35 +7,45 @@ use crate::{
impl Run for EightBitLoadInstruction {
// TODO: Break this up somehow
#[allow(clippy::too_many_lines)]
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
match *self {
EightBitLoadInstruction::LoadImmediateToRegister { value, register } => {
processor
.registers
.set_single_8bit_register(register, value);
Ok(())
Ok(Cycles(8))
}
EightBitLoadInstruction::LoadBetweenRegisters { dst, src } => {
let src_value = processor.registers.get_single_8bit_register(src);
processor.registers.set_single_8bit_register(dst, src_value);
Ok(())
Ok(Cycles(4))
}
EightBitLoadInstruction::LoadFromRegisterAddress { src, dst } => {
processor.load_from_register_address_to_register(dst, src)
processor.load_from_register_address_to_register(dst, src)?;
Ok(Cycles(8))
}
EightBitLoadInstruction::LoadFromImmediateAddress { src_address, dst } => {
processor.load_from_address_to_register(dst, src_address.into())
processor.load_from_address_to_register(dst, src_address.into())?;
Ok(Cycles(16))
}
EightBitLoadInstruction::LoadToRegisterAddress { src, dst } => {
processor.load_from_register_to_register_address(dst, src)
processor.load_from_register_to_register_address(dst, src)?;
Ok(Cycles(8))
}
EightBitLoadInstruction::LoadToImmediateAddress { src, dst_address } => {
processor.load_from_register_to_address(dst_address.into(), src)
processor.load_from_register_to_address(dst_address.into(), src)?;
Ok(Cycles(16))
}
EightBitLoadInstruction::LoadnToHLAddress { value } => {
@ -43,7 +53,9 @@ impl Run for EightBitLoadInstruction {
.registers
.get_combined_register(register::Combined::HL);
processor.load_8bit_immediate_to_address(dest_address.into(), value)
processor.load_8bit_immediate_to_address(dest_address.into(), value)?;
Ok(Cycles(12))
}
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStart {
@ -56,7 +68,8 @@ impl Run for EightBitLoadInstruction {
let src_address =
memory::IO_REGISTER_START_ADDRESS + usize::from(src_address_offset);
processor.load_from_address_to_register(dst, src_address)
processor.load_from_address_to_register(dst, src_address)?;
Ok(Cycles(8))
}
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStart {
@ -69,7 +82,9 @@ impl Run for EightBitLoadInstruction {
let dst_address =
memory::IO_REGISTER_START_ADDRESS + usize::from(dst_address_offset);
processor.load_from_register_to_address(dst_address, src)
processor.load_from_register_to_address(dst_address, src)?;
Ok(Cycles(8))
}
EightBitLoadInstruction::LoadFromRegisterAddressThenDec { dst, src } => {
@ -80,7 +95,7 @@ impl Run for EightBitLoadInstruction {
.registers
.set_combined_register(src, src_address - 1);
Ok(())
Ok(Cycles(8))
}
EightBitLoadInstruction::LoadFromRegisterAddressThenInc { dst, src } => {
@ -91,7 +106,7 @@ impl Run for EightBitLoadInstruction {
.registers
.set_combined_register(src, src_address + 1);
Ok(())
Ok(Cycles(8))
}
EightBitLoadInstruction::LoadToRegisterAddressThenDec { dst, src } => {
@ -102,7 +117,7 @@ impl Run for EightBitLoadInstruction {
.registers
.set_combined_register(dst, dst_address - 1);
Ok(())
Ok(Cycles(8))
}
EightBitLoadInstruction::LoadToRegisterAddressThenInc { dst, src } => {
@ -113,7 +128,7 @@ impl Run for EightBitLoadInstruction {
.registers
.set_combined_register(dst, dst_address + 1);
Ok(())
Ok(Cycles(8))
}
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
@ -121,7 +136,9 @@ impl Run for EightBitLoadInstruction {
offset,
} => {
let dst_address = memory::IO_REGISTER_START_ADDRESS + usize::from(offset);
processor.load_from_register_to_address(dst_address, src)
processor.load_from_register_to_address(dst_address, src)?;
Ok(Cycles(12))
}
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStartByImmediate {
@ -129,7 +146,9 @@ impl Run for EightBitLoadInstruction {
offset,
} => {
let src_address = memory::IO_REGISTER_START_ADDRESS + usize::from(offset);
processor.load_from_address_to_register(dst, src_address)
processor.load_from_address_to_register(dst, src_address)?;
Ok(Cycles(12))
}
}
}

View File

@ -3,15 +3,15 @@ use crate::{
register::Registers,
};
use super::Run;
use super::{Cycles, Run};
impl Run for MiscInstruction {
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
match *self {
MiscInstruction::SetCarryFlag => {
set_flags_in_carry_bit_instruction(processor, 1);
Ok(())
Ok(Cycles(4))
}
MiscInstruction::ComplementCarryFlag => {
let current_carry_flag = processor.registers.get_flag_bit(register::Flag::Carry);
@ -19,7 +19,7 @@ impl Run for MiscInstruction {
set_flags_in_carry_bit_instruction(processor, flipped);
Ok(())
Ok(Cycles(4))
}
MiscInstruction::ComplementARegister => {
let current_value = processor
@ -36,7 +36,7 @@ impl Run for MiscInstruction {
.registers
.set_flag_bit(register::Flag::Subtract, 1);
Ok(())
Ok(Cycles(4))
}
MiscInstruction::DecimalAdjustAccumulator => {
let (adjusted_a_value, carry) = get_daa_value(&processor.registers);
@ -57,7 +57,7 @@ impl Run for MiscInstruction {
.registers
.set_flag_bit(register::Flag::Zero, (adjusted_a_value == 0).into());
Ok(())
Ok(Cycles(4))
}
}
}

View File

@ -1,5 +1,5 @@
use ferris_boi::{
cpu::{instructions::RunnableInstruction, Processor},
cpu::{instructions::Instruction, Processor},
register,
};
@ -21,11 +21,10 @@ fn test_add_hl_to_itself() {
);
let data = [0x29, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0x4488,
@ -60,11 +59,10 @@ fn test_add_hl_to_registers_value(
.set_16bit_register(operand_register, operand_value);
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
expected,
@ -102,8 +100,7 @@ fn test_add_hl_to_registers_flags(
.set_16bit_register(operand_register, operand_value);
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
// Set all the register to the opposite we expect to ensure they all get set
@ -112,7 +109,7 @@ fn test_add_hl_to_registers_flags(
(0, 0, expected_flags.half_carry, expected_flags.carry),
);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -150,11 +147,10 @@ fn test_increment(
.expect("Failed to set flag bits");
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
expected,
@ -191,11 +187,10 @@ fn test_decrement(
.expect("Failed to set flag bits");
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
expected,

View File

@ -1,5 +1,5 @@
use ferris_boi::{
cpu::{instructions::RunnableInstruction, Processor},
cpu::{instructions::Instruction, Processor},
register,
};
@ -25,11 +25,10 @@ fn test_add_a_to_itself() {
processor.registers.a = 10;
let data = [0x87, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(20, processor.registers.a);
}
@ -46,11 +45,10 @@ fn test_add_to_a_value(opcode: u8, src: register::SingleEightBit) {
processor.registers.set_single_8bit_register(src, 20);
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(30, processor.registers.a);
}
@ -93,11 +91,10 @@ fn test_add_register_to_a_flags(
processor.registers.set_single_8bit_register(src, src_value);
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -123,11 +120,10 @@ fn test_add_hl_addr_to_a_value() {
let data = [0x86, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0x46, processor.registers.a);
}
@ -166,11 +162,10 @@ fn test_add_hl_addr_to_a_flags(
);
let data = [0x86, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -187,11 +182,10 @@ fn test_add_immediate_to_a_value() {
processor.registers.a = 50;
let data = [0xC6, 0x13, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(69, processor.registers.a);
}
@ -217,11 +211,10 @@ fn test_add_immediate_to_a_flags(a_value: u8, n: u8, expected_flags: AdditionOpe
);
let data = [0xC6, n, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -260,10 +253,9 @@ fn test_add_register_with_carry_to_a_value(
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [opcode, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(expected_value, processor.registers.a);
}
@ -323,10 +315,9 @@ fn test_add_register_with_carry_to_a_flags(
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [opcode, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -347,10 +338,9 @@ fn test_add_a_to_itself_with_carry_value(initial_value: u8, carry_bit: u8, expec
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0x8F, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(processor.registers.a, expected_value);
}
@ -381,10 +371,9 @@ fn test_add_a_to_itself_with_carry_flags(
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0x8F, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -410,10 +399,9 @@ fn test_add_immediate_with_carry_to_a_value(
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0xCE, operand, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(processor.registers.a, expected_value);
}
@ -446,10 +434,9 @@ fn test_add_immediate_with_carry_to_a_flags(
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0xCE, operand, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -479,11 +466,10 @@ fn test_add_hl_addr_to_a_with_carry_value(carry_flag: u8, expected: u8) {
let data = [0x8E, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(expected, processor.registers.a);
}
@ -526,11 +512,10 @@ fn test_add_hl_addr_to_a_with_carry_flags(
let data = [0x8E, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -567,11 +552,10 @@ fn test_sub_register_from_a_value(
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(processor.registers.a, expected);
}
@ -613,11 +597,10 @@ fn test_sub_register_from_a_flags(
);
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -634,14 +617,13 @@ fn test_sub_a_from_itself() {
processor.registers.a = 0xFF;
let data = [0x97, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
// Set all the register to the opposite we expect to ensure they all get set
testutil::set_opposite_of_expected_flags(&mut processor, (0, 0, 1, 1));
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -681,11 +663,10 @@ fn test_sub_register_with_carry_from_a_value(
let data = [opcode, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(processor.registers.a, expected);
}
#[test_matrix(
@ -739,10 +720,9 @@ fn test_sub_register_from_carry_from_a_flags(
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [opcode, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -759,11 +739,10 @@ fn test_subtract_immediate_from_a_value() {
processor.registers.a = 0xFF;
let data = [0xD6, 0x0F, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(processor.registers.a, 0xF0);
}
@ -791,10 +770,9 @@ fn test_sub_immediate_from_a_flags(
);
let data = [0xD6, operand, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -821,11 +799,10 @@ fn test_sub_immediate_with_carry_from_a_value(
let data = [0xDE, operand, 0x02];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(processor.registers.a, expected);
}
@ -864,10 +841,9 @@ fn test_sub_immediate_from_carry_from_a_flags(
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0xDE, operand, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -888,10 +864,9 @@ fn test_sub_a_register_from_itself_with_carry_value(carry_bit: u8, expected: u8)
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0x9F, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(expected, processor.registers.a);
}
@ -920,10 +895,9 @@ fn test_sub_a_register_from_itself_with_carry_flags(
.set_flag_bit(register::Flag::Carry, carry_bit);
let data = [0x9F, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -948,10 +922,9 @@ fn test_sub_hl_addr_from_a_value() {
.set_combined_register(register::Combined::HL, 0xABCD);
let data = [0x96, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0x11, processor.registers.a);
}
@ -988,10 +961,9 @@ fn test_sub_hl_addr_from_a_flags(
.set_combined_register(register::Combined::HL, 0xABCD);
let data = [0x96, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1020,10 +992,9 @@ fn test_sub_hl_from_a_flags(a_value: u8, operand_value: u8, carry_bit: u8, expec
.set_combined_register(register::Combined::HL, 0xABCD);
let data = [0x9E, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(expected_value, processor.registers.a);
}
@ -1069,10 +1040,9 @@ fn test_sub_hl_addr_from_a_with_carry_flags(
.set_combined_register(register::Combined::HL, 0xABCD);
let data = [0x9E, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1103,10 +1073,9 @@ fn test_and_single_register_with_a_value(
.set_single_8bit_register(operand_register, operand);
let data = [opcode, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(expected_value, processor.registers.a);
}
@ -1137,10 +1106,9 @@ fn test_and_single_register_with_a_flags(
.set_single_8bit_register(operand_register, operand);
let data = [opcode, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1157,10 +1125,9 @@ fn test_and_a_with_itself_value() {
processor.registers.a = 0xAB;
let data = [0xA7, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0xAB, processor.registers.a);
}
@ -1174,10 +1141,9 @@ fn test_and_a_with_itself_flags() {
processor.registers.a = 0xAB;
let data = [0xA7, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1201,10 +1167,9 @@ fn test_and_hl_value_with_a_value() {
.expect("failed to set value");
let data = [0xA6, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0xA0, processor.registers.a);
}
@ -1226,10 +1191,9 @@ fn test_and_hl_value_with_a_flags(a_value: u8, operand: u8, expected_zero_flag:
testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 1, 0));
let data = [0xA6, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1246,10 +1210,9 @@ fn test_and_immediate_with_a_value() {
processor.registers.a = 0xAB;
let data = [0xE6, 0x0F, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0x0B, processor.registers.a);
}
@ -1264,10 +1227,9 @@ fn test_and_immediate_with_a_flags(a_value: u8, operand: u8, expected_zero_flag:
testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 1, 0));
let data = [0xE6, operand, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1300,10 +1262,9 @@ fn test_xor_register_with_a_value(
.set_single_8bit_register(operand_register, operand);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(expected_value, processor.registers.a);
}
@ -1336,10 +1297,9 @@ fn test_xor_register_with_a_flags(
.set_single_8bit_register(operand_register, operand);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1356,10 +1316,9 @@ fn test_xor_register_a_with_itself_value() {
processor.registers.a = 0x45;
let data = [0xAF, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0, processor.registers.a);
}
@ -1372,10 +1331,9 @@ fn test_xor_register_a_with_itself_flags() {
processor.registers.a = 0x45;
let data = [0xAF, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1402,10 +1360,9 @@ fn test_xor_hl_value_with_a_value() {
.expect("failed to set memory value");
let data = [0xAE, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0x55, processor.registers.a);
}
@ -1428,10 +1385,9 @@ fn test_xor_hl_value_with_a_flags(a_value: u8, operand: u8, expected_zero_flag:
.expect("failed to set memory value");
let data = [0xAE, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1450,10 +1406,9 @@ fn test_xor_immediate_value_with_a_value() {
.set_single_8bit_register(register::SingleEightBit::A, 0x22);
let data = [0xEE, 0xEE, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0xCC, processor.registers.a);
}
@ -1468,10 +1423,9 @@ fn test_xor_immediate_value_with_a_flags(a_value: u8, operand: u8, expected_zero
.set_single_8bit_register(register::SingleEightBit::A, a_value);
let data = [0xEE, operand, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1509,10 +1463,9 @@ fn test_or_register_with_a_value(
.set_single_8bit_register(operand_register, operand);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(expected_value, processor.registers.a);
}
@ -1545,10 +1498,9 @@ fn test_or_register_with_a_flags(
.set_single_8bit_register(operand_register, operand);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1565,10 +1517,9 @@ fn test_or_register_a_with_itself_value() {
processor.registers.a = 0x45;
let data = [0xB7, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0x45, processor.registers.a);
}
@ -1582,10 +1533,9 @@ fn test_or_register_a_with_itself_flags(operand: u8, expected_zero_flag: u8) {
processor.registers.a = operand;
let data = [0xB7, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1612,10 +1562,9 @@ fn test_or_hl_value_with_a_value() {
.expect("failed to set memory value");
let data = [0xB6, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0xBB, processor.registers.a);
}
@ -1639,10 +1588,9 @@ fn test_or_hl_value_with_a_flags(a_value: u8, hl_value: u8, expected_zero_flag:
.expect("failed to set memory value");
let data = [0xB7, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1661,10 +1609,9 @@ fn test_or_immediate_value_with_a_value() {
.set_single_8bit_register(register::SingleEightBit::A, 0x33);
let data = [0xF6, 0xAA, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0xBB, processor.registers.a);
}
@ -1679,10 +1626,9 @@ fn test_or_immediate_value_with_a_flags(a_value: u8, operand: u8, expected_zero_
.set_single_8bit_register(register::SingleEightBit::A, a_value);
let data = [0xF6, operand, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1710,10 +1656,9 @@ fn test_compare_register_instructions_do_not_modify_register_values(
processor.registers.set_single_8bit_register(register, 0x22);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0xFF,
@ -1733,10 +1678,9 @@ fn test_compare_register_with_itself_does_not_modify_value() {
.set_single_8bit_register(register::SingleEightBit::A, 0xFF);
let data = [0xBF, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0xFF,
@ -1767,10 +1711,9 @@ fn test_comparing_equal_values_between_registers_sets_zero_flag(
processor.registers.set_single_8bit_register(register, 0xFF);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0xFF,
@ -1808,10 +1751,9 @@ fn test_comparing_extremely_less_than_values_between_registers_should_set_no_fla
processor.registers.set_single_8bit_register(register, 0x01);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1842,10 +1784,9 @@ fn test_comparing_extremely_somewhat_less_than_values_between_registers_should_s
processor.registers.set_single_8bit_register(register, 0x1F);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1876,10 +1817,9 @@ fn test_comparing_greater_than_values_between_registers_should_set_carry_flag(
processor.registers.set_single_8bit_register(register, 0xFF);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1910,10 +1850,9 @@ fn test_comparing_lower_nibble_greater_than_values_between_registers_should_set_
processor.registers.set_single_8bit_register(register, 0x2F);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -1940,10 +1879,9 @@ fn test_comparing_hl_value_to_a_does_not_change_value() {
.expect("failde to set value");
let data = [0xBE, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0xFF,
@ -1984,10 +1922,9 @@ fn test_comparing_hl_value_to_a(a_value: u8, operand: u8, expected_flags: Additi
);
let data = [0xBE, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -2006,10 +1943,9 @@ fn test_comparing_immediate_value_to_a_does_not_change_value() {
.set_single_8bit_register(register::SingleEightBit::A, 0xFF);
let data = [0xFE, 0xBB, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0xFF,
@ -2046,10 +1982,9 @@ fn test_comparing_immediate_value_to_a(
);
let data = [0xFE, operand, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -2102,10 +2037,9 @@ fn test_increment_decrement_single_register_value(
.set_single_8bit_register(register, initial_value);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
expected_value,
@ -2168,10 +2102,9 @@ fn test_increment_decrement_single_register_flags(
);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -2198,10 +2131,9 @@ fn test_increment_decrement_hl_value(opcode: u8, initial_value: u8, expected_val
.expect("failed to set memory value");
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
expected_value,
@ -2246,10 +2178,9 @@ fn test_increment_decrement_hl_flags(
);
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -2273,10 +2204,9 @@ fn test_adjust_stack_pointer_value(initial_sp: u16, adjustment: i8, expected_sp:
let twos_comp_adjustment = adjustment.to_be_bytes()[0];
let data = [0xE8, twos_comp_adjustment, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(expected_sp, processor.registers.stack_pointer);
}
@ -2298,10 +2228,9 @@ fn test_adjust_stack_pointer(initial_sp: u16, adjustment: i8, half_carry: bool,
let twos_comp_adjustment = adjustment.to_be_bytes()[0];
let data = [0xE8, twos_comp_adjustment, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,

View File

@ -1,5 +1,5 @@
use ferris_boi::{
cpu::{instructions::RunnableInstruction, Processor},
cpu::{instructions::Instruction, Processor},
register,
};
@ -21,11 +21,10 @@ fn test_load_to_register_address_then_do_arithmetic(
processor.registers.a = 10;
let data = [opcode, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(10, processor.memory.get(hl_value_before.into()).unwrap());
assert_eq!(
hl_value_after,
@ -51,11 +50,10 @@ fn test_load_16bit_immediate_to_register(opcode: u8, expected_dst_register: regi
// l05c0: ld hl,0ff02h ; 05c0 21 02 ff !..
let data = [opcode, 0x34, 0x12, 0x05];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x05]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0x1234,
@ -73,11 +71,10 @@ fn test_load_from_hl_to_sp() {
.set_combined_register(register::Combined::HL, 0x1234);
let data = [0xF9, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0x1234, processor.registers.stack_pointer);
}
@ -106,11 +103,10 @@ fn test_load_effective_address(start_sp: u16, value: i8, expected_sp: u16) {
let data = [0xF8, unsigned_value, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
expected_sp,
@ -142,11 +138,10 @@ fn test_load_effective_address_flags(starting_sp: u16, add_value: i8, half_carry
};
let data = [0xF8, unsigned_value, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -166,11 +161,10 @@ fn test_stack_push(opcode: u8, src: register::Combined) {
processor.registers.stack_pointer = 0xFFFE;
let data = [opcode, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
// we want to pop the LSB first (i.e. we write the MSB first)
// https://rgbds.gbdev.io/docs/v0.5.2/gbz80.7#PUSH_r16
@ -188,11 +182,10 @@ fn test_stack_push_from_af() {
processor.registers.stack_pointer = 0xFFFE;
let data = [0xF5, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
// we want to pop the LSB first (i.e. we write the MSB first)
// https://rgbds.gbdev.io/docs/v0.5.2/gbz80.7#PUSH_r16
@ -213,11 +206,10 @@ fn test_stack_pop(opcode: u8, dst: register::Combined) {
.expect("failed to set values in memory");
let data = [opcode, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0x1234, processor.registers.get_combined_register(dst));
assert_eq!(0xFFF0 + 2, processor.registers.stack_pointer);
@ -233,11 +225,10 @@ fn test_stack_pop_to_af() {
.expect("failed to set values in memory");
let data = [0xF1, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0x1230,

View File

@ -1,5 +1,5 @@
use ferris_boi::{
cpu::{instructions::RunnableInstruction, Processor},
cpu::{instructions::Instruction, Processor},
register,
};
use test_case::test_case;
@ -65,13 +65,12 @@ fn test_load_register(
.set_single_8bit_register(src_register, 0x45);
let data = [load_opcode, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
// assert our extra data after the instruction is returned
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0x45,
processor.registers.get_single_8bit_register(dst_register)
@ -88,14 +87,13 @@ fn test_load_register(
fn test_load_immediate(load_opcode: u8, expected_register: register::SingleEightBit) {
let mut processor = Processor::default();
let data = [load_opcode, 0x23, 0x00, 0x01];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
// assert our extra data after the instruction is returned
// this data is just garbage; no idea if it's a valid instruction
assert_eq!(extra_data, &[0x00, 0x01]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
0x23,
processor
@ -127,12 +125,11 @@ fn test_load_from_memory(
.set_combined_register(expected_deref_register, 0xCCDD);
let data = [opcode, 0x10, 0x20];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse isntruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse isntruction");
assert_eq!(extra_data, &[0x10, 0x20]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(
105,
processor
@ -168,12 +165,11 @@ fn test_load_to_memory(
.set_combined_register(expected_deref_register, 0xCCCC);
let data = [opcode, 0x10, 0x20];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x10, 0x20]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0xCC, processor.memory.get(0xCCCC).unwrap());
}
@ -185,11 +181,10 @@ fn test_load_immediate_to_memory() {
.set_combined_register(register::Combined::HL, 0xCCDE);
let data = [0x36, 0x1D, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0x1D, processor.memory.get(0xCCDE).unwrap());
}
@ -202,11 +197,10 @@ fn test_load_from_immediate_address() {
.expect("failed to set memory value");
let data = [0xFA, 0xDE, 0xCC, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(105, processor.registers.a);
}
@ -215,11 +209,10 @@ fn test_load_to_immadiate_address() {
let mut processor = Processor::default();
processor.registers.a = 105;
let data = [0xEA, 0xDE, 0xCC, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(105, processor.memory.get(0xCCDE).unwrap());
}
@ -233,11 +226,10 @@ fn test_load_from_io_register_zone() {
processor.registers.c = 0x64;
let data = [0xF2, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(10, processor.registers.a);
}
@ -248,11 +240,10 @@ fn test_load_to_io_register_zone() {
processor.registers.a = 10;
let data = [0xE2, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(10, processor.memory.get(0xFF64).unwrap());
}
@ -273,11 +264,10 @@ fn test_load_from_register_address_then_do_arithmetic(
.expect("failed to set memory value");
let data = [opcode, 0x00];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x00]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(10, processor.registers.a);
assert_eq!(
hl_value_after,
@ -293,11 +283,10 @@ fn test_load_to_io_register_zone_by_immediate() {
processor.registers.a = 0xAF;
let data = [0xE0, 0x05, 0x06];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x06]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0xAF, processor.memory.get(0xFF05).unwrap());
}
@ -311,11 +300,10 @@ fn test_load_from_io_register_zone_by_immediate() {
.expect("failed to set memory value");
let data = [0xF0, 0x05, 0x06];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x06]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0xAF, processor.registers.a);
}
@ -326,12 +314,11 @@ fn test_load_from_bottom_of_so_to_immediate_address() {
processor.registers.stack_pointer = 0xABCD;
let data = [0x08, 0xAA, 0xFF, 0x06];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x06]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
let bottom_stored_value = processor.memory.get_from(0xFFAA).unwrap().get();
let top_stored_value = processor.memory.get_from(0xFFAB).unwrap().get();

View File

@ -1,6 +1,6 @@
use crate::testutil::{self, assert_flags_eq};
use ferris_boi::{
cpu::{instructions::RunnableInstruction, Processor},
cpu::{instructions::Instruction, Processor},
register,
};
use test_case::test_case;
@ -25,11 +25,10 @@ fn test_set_carry_flag_always_sets_to_1(starting_value: u8) {
.set_flag_bit(register::Flag::Carry, starting_value);
let data = [0x37, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
let new_carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
assert_eq!(1, new_carry_bit);
@ -44,11 +43,10 @@ fn test_complement_carry_bit(starting_value: u8, expected_value: u8) {
.set_flag_bit(register::Flag::Carry, starting_value);
let data = [0x3F, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
let new_carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
assert_eq!(expected_value, new_carry_bit);
@ -61,11 +59,10 @@ fn test_all_carry_bit_instructions_adjust_flags(opcode: u8) {
testutil::set_opposite_of_expected_flags(&mut processor, (0, 0, 0, 1));
let data = [opcode, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -84,11 +81,10 @@ fn test_complement_a_register_value() {
processor.registers.a = 0xF0;
let data = [0x2F, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(0x0F, processor.registers.a);
}
@ -100,11 +96,10 @@ fn test_complement_a_register_flags() {
testutil::set_opposite_of_expected_flags(&mut processor, (0, 1, 1, 0));
let data = [0x2F, 0x03];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x03]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
testutil::assert_flags_eq!(
processor,
@ -150,11 +145,10 @@ fn test_daa(
.set_flag_bit(register::Flag::Zero, (!expected_flags.zero).into());
let data = [0x27, 0x06];
let (ins, extra_data) =
RunnableInstruction::from_data(&data).expect("could not parse instruction");
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x06]);
processor.run_instruction(&ins);
processor.run_instruction(ins);
assert_eq!(expected_a_value, processor.registers.a);
assert_flags_eq!(