Remove RunnableInstruction, encode cycles as a result of runtime
This is necessary for certain instructions, since they can take a different number of cyclesold-bit-manip
parent
f9cdccb5fd
commit
b5117e7cf9
10
src/cpu.rs
10
src/cpu.rs
|
@ -1,4 +1,4 @@
|
||||||
use instructions::RunnableInstruction;
|
use instructions::Instruction;
|
||||||
use run::Error;
|
use run::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -32,7 +32,7 @@ impl Processor {
|
||||||
let (instruction, bytes_read) =
|
let (instruction, bytes_read) =
|
||||||
parse::next_instruction(&memory_view).expect("invalid instruction");
|
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);
|
let (next_pc, _carry) = pc.overflowing_add(bytes_read);
|
||||||
self.registers.program_counter = next_pc;
|
self.registers.program_counter = next_pc;
|
||||||
|
@ -42,13 +42,13 @@ impl Processor {
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if an internal error occurred within the CPU. These are always bugs.
|
/// Panics if an internal error occurred within the CPU. These are always bugs.
|
||||||
pub fn run_instruction(&mut self, instruction: &RunnableInstruction) {
|
pub fn run_instruction(&mut self, instruction: Instruction) {
|
||||||
let run_res = run::run_instruction(self, instruction.instruction);
|
let run_res = run::run_instruction(self, instruction);
|
||||||
if let Err(err) = run_res {
|
if let Err(err) = run_res {
|
||||||
panic!("Fatal CPU error occured: {err}")
|
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(
|
fn load_from_register_to_register_address(
|
||||||
|
|
|
@ -22,14 +22,7 @@ pub enum Instruction {
|
||||||
Misc(misc::MiscInstruction),
|
Misc(misc::MiscInstruction),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `RunnableInstruction` is an instruction that can run on the processor, and has any metadata needed to do so
|
impl Instruction {
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct RunnableInstruction {
|
|
||||||
pub(super) instruction: Instruction,
|
|
||||||
pub(super) cycles: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RunnableInstruction {
|
|
||||||
/// `from_data` will produce an instruction from the given data and return the data after
|
/// `from_data` will produce an instruction from the given data and return the data after
|
||||||
/// processing that operation.
|
/// processing that operation.
|
||||||
///
|
///
|
||||||
|
@ -37,7 +30,7 @@ impl RunnableInstruction {
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Returns an error if the instruction couldn't be parsed.
|
/// 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))
|
parse::next_instruction(&View::new_from_data(data, 0))
|
||||||
.map(|(ins, offset)| (ins, &data[offset.into()..]))
|
.map(|(ins, offset)| (ins, &data[offset.into()..]))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use crate::memory::View;
|
use crate::memory::View;
|
||||||
|
|
||||||
use super::instructions::RunnableInstruction;
|
use super::instructions::Instruction;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
mod arith16;
|
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.
|
/// `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>;
|
pub(super) type ParseResult = Result<ParseOutput, Error>;
|
||||||
|
|
||||||
/// `OpcodeParser` takes input data, parses out an opcode (and its associated arguments) if it can, and returns
|
/// `OpcodeParser` takes input data, parses out an opcode (and its associated arguments) if it can, and returns
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
cpu::{
|
cpu::{
|
||||||
|
instructions::arith16::SixteenBitArithmeticInstruction,
|
||||||
instructions::Instruction,
|
instructions::Instruction,
|
||||||
instructions::{arith16::SixteenBitArithmeticInstruction, RunnableInstruction},
|
|
||||||
parse::{self, Error, OpcodeParser, ParseResult},
|
parse::{self, Error, OpcodeParser, ParseResult},
|
||||||
register::{Combined, SingleSixteenBit, SixteenBit},
|
register::{Combined, SingleSixteenBit, SixteenBit},
|
||||||
},
|
},
|
||||||
|
@ -49,36 +49,27 @@ impl OpcodeParser for Parser {
|
||||||
|
|
||||||
fn build_add_hl_to_register_data(operand_register: SixteenBit) -> ParseOutput {
|
fn build_add_hl_to_register_data(operand_register: SixteenBit) -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::SixteenBitArithmetic(SixteenBitArithmeticInstruction::AddRegisterToHL {
|
||||||
instruction: Instruction::SixteenBitArithmetic(
|
operand_register,
|
||||||
SixteenBitArithmeticInstruction::AddRegisterToHL { operand_register },
|
}),
|
||||||
),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_inc_register_data(operand_register: SixteenBit) -> ParseOutput {
|
fn build_inc_register_data(operand_register: SixteenBit) -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::SixteenBitArithmetic(SixteenBitArithmeticInstruction::IncrementRegister {
|
||||||
instruction: Instruction::SixteenBitArithmetic(
|
operand_register,
|
||||||
SixteenBitArithmeticInstruction::IncrementRegister { operand_register },
|
}),
|
||||||
),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_dec_register_data(operand_register: SixteenBit) -> ParseOutput {
|
fn build_dec_register_data(operand_register: SixteenBit) -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::SixteenBitArithmetic(SixteenBitArithmeticInstruction::DecrementRegister {
|
||||||
instruction: Instruction::SixteenBitArithmetic(
|
operand_register,
|
||||||
SixteenBitArithmeticInstruction::DecrementRegister { operand_register },
|
}),
|
||||||
),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
arith8::{
|
arith8::{
|
||||||
AdjustStackPointerInstruction, EightBitArithmeticInstruction, Operand, Operation,
|
AdjustStackPointerInstruction, EightBitArithmeticInstruction, Operand, Operation,
|
||||||
},
|
},
|
||||||
Instruction, RunnableInstruction,
|
Instruction,
|
||||||
},
|
},
|
||||||
memory::{GetViewTuple, View},
|
memory::{GetViewTuple, View},
|
||||||
register,
|
register,
|
||||||
|
@ -35,28 +35,12 @@ fn parse_eight_bit_arithmetic_instruction(data: &View) -> super::ParseResult {
|
||||||
let operation = operation_for_opcode(opcode)?;
|
let operation = operation_for_opcode(opcode)?;
|
||||||
let operand = operand_for_opcode(opcode)?;
|
let operand = operand_for_opcode(opcode)?;
|
||||||
|
|
||||||
let parse_data = match (operation, operand) {
|
let parse_data = match operand {
|
||||||
(_operation, OpcodeOperand::SingleRegister(register)) => {
|
OpcodeOperand::SingleRegister(register) => {
|
||||||
build_instruction_between_register_and_a_data(operation, register)
|
build_instruction_between_register_and_a_data(operation, register)
|
||||||
}
|
}
|
||||||
(Operation::Inc | Operation::Dec, OpcodeOperand::HLAddressValue) => {
|
OpcodeOperand::HLAddressValue => build_instruction_between_hl_value_and_a_data(operation),
|
||||||
let (runnable_ins, bytes_read) =
|
OpcodeOperand::Immediate => build_instruction_between_immediate_and_a_data(operation, data),
|
||||||
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)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(parse_data)
|
Ok(parse_data)
|
||||||
|
@ -157,13 +141,7 @@ fn build_instruction_between_register_and_a_data(
|
||||||
operation,
|
operation,
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(Instruction::EightBitArithmetic(instruction), 1)
|
||||||
RunnableInstruction {
|
|
||||||
instruction: Instruction::EightBitArithmetic(instruction),
|
|
||||||
cycles: 4,
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_instruction_between_hl_value_and_a_data(operation: Operation) -> ParseOutput {
|
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,
|
operation,
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(Instruction::EightBitArithmetic(instruction), 1)
|
||||||
RunnableInstruction {
|
|
||||||
instruction: Instruction::EightBitArithmetic(instruction),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_instruction_between_immediate_and_a_data(
|
fn build_instruction_between_immediate_and_a_data(
|
||||||
|
@ -192,13 +164,7 @@ fn build_instruction_between_immediate_and_a_data(
|
||||||
operation,
|
operation,
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(Instruction::EightBitArithmetic(instruction), 2)
|
||||||
RunnableInstruction {
|
|
||||||
instruction: Instruction::EightBitArithmetic(instruction),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
2,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stack_pointer_adjust_data(data: &View) -> ParseOutput {
|
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]),
|
operand: i8::from_be_bytes([n]),
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(Instruction::StackPointerAdjust(instruction), 2)
|
||||||
RunnableInstruction {
|
|
||||||
instruction: Instruction::StackPointerAdjust(instruction),
|
|
||||||
cycles: 16,
|
|
||||||
},
|
|
||||||
2,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
|
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
|
||||||
use crate::cpu::parse::ParseOutput;
|
use crate::cpu::parse::ParseOutput;
|
||||||
use crate::cpu::{
|
use crate::cpu::{
|
||||||
instructions::{Instruction, RunnableInstruction},
|
instructions::Instruction,
|
||||||
parse::{self, Error, OpcodeParser, ParseResult},
|
parse::{self, Error, OpcodeParser, ParseResult},
|
||||||
};
|
};
|
||||||
use crate::memory::{GetViewTuple, View};
|
use crate::memory::{GetViewTuple, View};
|
||||||
|
@ -44,12 +44,10 @@ fn make_load_immediate_data(dst: register::SixteenBit, data: &View) -> ParseOutp
|
||||||
// indicates it should be.
|
// indicates it should be.
|
||||||
let value = u16::from_le_bytes([lower_bytes, upper_bytes]);
|
let value = u16::from_le_bytes([lower_bytes, upper_bytes]);
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::LoadImmediateToRegister {
|
||||||
instruction: Instruction::SixteenBitLoad(
|
value,
|
||||||
SixteenBitLoadInstruction::LoadImmediateToRegister { value, dst },
|
dst,
|
||||||
),
|
}),
|
||||||
cycles: 12,
|
|
||||||
},
|
|
||||||
3,
|
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]);
|
let signed_value = i8::from_be_bytes([unsigned_value]);
|
||||||
|
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::LoadEffectiveAddress {
|
||||||
instruction: Instruction::SixteenBitLoad(
|
dst,
|
||||||
SixteenBitLoadInstruction::LoadEffectiveAddress {
|
offset: signed_value,
|
||||||
dst,
|
}),
|
||||||
offset: signed_value,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
cycles: 12,
|
|
||||||
},
|
|
||||||
2,
|
2,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
|
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::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult};
|
||||||
use crate::memory::{GetViewTuple, View};
|
use crate::memory::{GetViewTuple, View};
|
||||||
use crate::register;
|
use crate::register;
|
||||||
|
@ -59,14 +59,10 @@ impl OpcodeParser for Parser {
|
||||||
|
|
||||||
fn make_stack_operation_data(operation: Operation, reg: register::Combined) -> ParseOutput {
|
fn make_stack_operation_data(operation: Operation, reg: register::Combined) -> ParseOutput {
|
||||||
let instruction = match operation {
|
let instruction = match operation {
|
||||||
Operation::Push => RunnableInstruction {
|
Operation::Push => {
|
||||||
instruction: Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Push { src: reg }),
|
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Push { src: reg })
|
||||||
cycles: 16,
|
}
|
||||||
},
|
Operation::Pop => Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Pop { dst: reg }),
|
||||||
Operation::Pop => RunnableInstruction {
|
|
||||||
instruction: Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Pop { dst: reg }),
|
|
||||||
cycles: 12,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(instruction, 1)
|
(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]);
|
let dst_address = u16::from_le_bytes([address_half1, address_half2]);
|
||||||
|
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::SixteenBitLoad(
|
||||||
instruction: Instruction::SixteenBitLoad(
|
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address },
|
||||||
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address },
|
),
|
||||||
),
|
|
||||||
cycles: 20,
|
|
||||||
},
|
|
||||||
3,
|
3,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
|
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
|
||||||
use crate::cpu::instructions::Instruction;
|
use crate::cpu::instructions::Instruction;
|
||||||
use crate::cpu::parse::ParseOutput;
|
use crate::cpu::parse::ParseOutput;
|
||||||
use crate::cpu::{
|
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
|
||||||
instructions::RunnableInstruction,
|
|
||||||
parse::{self, Error, OpcodeParser, ParseResult},
|
|
||||||
};
|
|
||||||
use crate::memory::View;
|
use crate::memory::View;
|
||||||
use crate::register;
|
use crate::register;
|
||||||
|
|
||||||
|
@ -29,12 +26,7 @@ fn make_load_between_register_data(
|
||||||
src: register::SixteenBit,
|
src: register::SixteenBit,
|
||||||
) -> ParseOutput {
|
) -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src }),
|
||||||
instruction: Instruction::SixteenBitLoad(
|
|
||||||
SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src },
|
|
||||||
),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use crate::cpu::instructions::load8::EightBitLoadInstruction;
|
use crate::cpu::instructions::load8::EightBitLoadInstruction;
|
||||||
use crate::cpu::instructions::Instruction;
|
use crate::cpu::instructions::Instruction;
|
||||||
use crate::cpu::parse::ParseOutput;
|
use crate::cpu::parse::ParseOutput;
|
||||||
use crate::cpu::{
|
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
|
||||||
instructions::RunnableInstruction,
|
|
||||||
parse::{self, Error, OpcodeParser, ParseResult},
|
|
||||||
};
|
|
||||||
use crate::memory::{GetViewTuple, View};
|
use crate::memory::{GetViewTuple, View};
|
||||||
use crate::register;
|
use crate::register;
|
||||||
|
|
||||||
|
@ -34,16 +31,10 @@ fn make_load_immediate_data(register: register::SingleEightBit, data: &View) ->
|
||||||
let (_opcode, value) = data.get_tuple();
|
let (_opcode, value) = data.get_tuple();
|
||||||
|
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(EightBitLoadInstruction::LoadImmediateToRegister {
|
||||||
instruction: Instruction::EightBitLoad(
|
register,
|
||||||
EightBitLoadInstruction::LoadImmediateToRegister { register, value },
|
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,
|
|
||||||
},
|
|
||||||
2,
|
2,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::cpu::instructions::load8::EightBitLoadInstruction;
|
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::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult};
|
||||||
use crate::memory::{GetViewTuple, View};
|
use crate::memory::{GetViewTuple, View};
|
||||||
use crate::register;
|
use crate::register;
|
||||||
|
@ -186,12 +186,7 @@ fn make_load_from_register_address(
|
||||||
src: register::Combined,
|
src: register::Combined,
|
||||||
) -> ParseOutput {
|
) -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(EightBitLoadInstruction::LoadFromRegisterAddress { src, dst }),
|
||||||
instruction: Instruction::EightBitLoad(
|
|
||||||
EightBitLoadInstruction::LoadFromRegisterAddress { src, dst },
|
|
||||||
),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -201,12 +196,7 @@ fn make_load_to_register_address(
|
||||||
src: register::SingleEightBit,
|
src: register::SingleEightBit,
|
||||||
) -> ParseOutput {
|
) -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(EightBitLoadInstruction::LoadToRegisterAddress { src, dst }),
|
||||||
instruction: Instruction::EightBitLoad(
|
|
||||||
EightBitLoadInstruction::LoadToRegisterAddress { src, dst },
|
|
||||||
),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
1,
|
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)
|
// 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]);
|
let src_address = u16::from_le_bytes([lower_bytes, upper_bytes]);
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(EightBitLoadInstruction::LoadFromImmediateAddress {
|
||||||
instruction: Instruction::EightBitLoad(
|
src_address,
|
||||||
EightBitLoadInstruction::LoadFromImmediateAddress { src_address, dst },
|
dst,
|
||||||
),
|
}),
|
||||||
cycles: 16,
|
|
||||||
},
|
|
||||||
3,
|
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)
|
// 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]);
|
let dst_address = u16::from_le_bytes([lower_bytes, upper_bytes]);
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(EightBitLoadInstruction::LoadToImmediateAddress {
|
||||||
instruction: Instruction::EightBitLoad(
|
src,
|
||||||
EightBitLoadInstruction::LoadToImmediateAddress { src, dst_address },
|
dst_address,
|
||||||
),
|
}),
|
||||||
cycles: 16,
|
|
||||||
},
|
|
||||||
3,
|
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 {
|
fn make_load_n_to_hl_address(data: &View) -> ParseOutput {
|
||||||
let (_opcode, value) = data.get_tuple();
|
let (_opcode, value) = data.get_tuple();
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(EightBitLoadInstruction::LoadnToHLAddress { value }),
|
||||||
instruction: Instruction::EightBitLoad(EightBitLoadInstruction::LoadnToHLAddress {
|
|
||||||
value,
|
|
||||||
}),
|
|
||||||
cycles: 12,
|
|
||||||
},
|
|
||||||
2,
|
2,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -261,16 +242,12 @@ fn make_load_from_memory_relative_to_io_register_start(
|
||||||
dst: register::SingleEightBit,
|
dst: register::SingleEightBit,
|
||||||
) -> ParseOutput {
|
) -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(
|
||||||
instruction: Instruction::EightBitLoad(
|
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStart {
|
||||||
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStart {
|
offset_register,
|
||||||
offset_register,
|
dst,
|
||||||
dst,
|
},
|
||||||
},
|
),
|
||||||
),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
// guaranteed to succeed given we found the opcode
|
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -280,15 +257,12 @@ fn make_load_to_memory_relative_to_io_register_start(
|
||||||
src: register::SingleEightBit,
|
src: register::SingleEightBit,
|
||||||
) -> ParseOutput {
|
) -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(
|
||||||
instruction: Instruction::EightBitLoad(
|
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStart {
|
||||||
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStart {
|
src,
|
||||||
src,
|
offset_register,
|
||||||
offset_register,
|
},
|
||||||
},
|
),
|
||||||
),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
// guaranteed to succeed given we found the opcode
|
// guaranteed to succeed given we found the opcode
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
|
@ -301,16 +275,12 @@ fn make_load_to_memory_relative_to_io_register_start_by_immediate(
|
||||||
let (_opcode, offset) = data.get_tuple();
|
let (_opcode, offset) = data.get_tuple();
|
||||||
|
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(
|
||||||
instruction: Instruction::EightBitLoad(
|
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
|
||||||
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
|
src,
|
||||||
src,
|
offset,
|
||||||
offset,
|
},
|
||||||
},
|
),
|
||||||
),
|
|
||||||
// guaranteed to succeed given we got the value
|
|
||||||
cycles: 12,
|
|
||||||
},
|
|
||||||
2,
|
2,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -322,15 +292,12 @@ fn make_load_from_memory_relative_to_io_register_start_by_immediate(
|
||||||
let (_opcode, offset) = data.get_tuple();
|
let (_opcode, offset) = data.get_tuple();
|
||||||
|
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(
|
||||||
instruction: Instruction::EightBitLoad(
|
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStartByImmediate {
|
||||||
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStartByImmediate {
|
offset,
|
||||||
offset,
|
dst,
|
||||||
dst,
|
},
|
||||||
},
|
),
|
||||||
),
|
|
||||||
cycles: 12,
|
|
||||||
},
|
|
||||||
2,
|
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 {
|
fn make_load_and_do_arithmetic<F: Fn() -> EightBitLoadInstruction>(make: F) -> ParseOutput {
|
||||||
let load_instruction = make();
|
let load_instruction = make();
|
||||||
|
|
||||||
(
|
(Instruction::EightBitLoad(load_instruction), 1)
|
||||||
RunnableInstruction {
|
|
||||||
instruction: Instruction::EightBitLoad(load_instruction),
|
|
||||||
cycles: 8,
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use crate::cpu::instructions::load8::EightBitLoadInstruction;
|
use crate::cpu::instructions::load8::EightBitLoadInstruction;
|
||||||
use crate::cpu::instructions::Instruction;
|
use crate::cpu::instructions::Instruction;
|
||||||
use crate::cpu::parse::ParseOutput;
|
use crate::cpu::parse::ParseOutput;
|
||||||
use crate::cpu::{
|
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
|
||||||
instructions::RunnableInstruction,
|
|
||||||
parse::{self, Error, OpcodeParser, ParseResult},
|
|
||||||
};
|
|
||||||
use crate::memory::View;
|
use crate::memory::View;
|
||||||
use crate::register;
|
use crate::register;
|
||||||
|
|
||||||
|
@ -54,13 +51,7 @@ fn make_load_between_register_data(
|
||||||
src: register::SingleEightBit,
|
src: register::SingleEightBit,
|
||||||
) -> ParseOutput {
|
) -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::EightBitLoad(EightBitLoadInstruction::LoadBetweenRegisters { dst, src }),
|
||||||
instruction: Instruction::EightBitLoad(EightBitLoadInstruction::LoadBetweenRegisters {
|
|
||||||
dst,
|
|
||||||
src,
|
|
||||||
}),
|
|
||||||
cycles: 4,
|
|
||||||
},
|
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{OpcodeParser, ParseOutput, ParseResult};
|
use super::{OpcodeParser, ParseOutput, ParseResult};
|
||||||
use crate::{
|
use crate::{
|
||||||
cpu::instructions::{misc::MiscInstruction, Instruction, RunnableInstruction},
|
cpu::instructions::{misc::MiscInstruction, Instruction},
|
||||||
memory::View,
|
memory::View,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,41 +20,20 @@ impl OpcodeParser for Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_set_carry_flag_data() -> ParseOutput {
|
fn build_set_carry_flag_data() -> ParseOutput {
|
||||||
(
|
(Instruction::Misc(MiscInstruction::SetCarryFlag), 1)
|
||||||
RunnableInstruction {
|
|
||||||
instruction: Instruction::Misc(MiscInstruction::SetCarryFlag),
|
|
||||||
cycles: 4,
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_complement_carry_flag_data() -> ParseOutput {
|
fn build_complement_carry_flag_data() -> ParseOutput {
|
||||||
(
|
(Instruction::Misc(MiscInstruction::ComplementCarryFlag), 1)
|
||||||
RunnableInstruction {
|
|
||||||
instruction: Instruction::Misc(MiscInstruction::ComplementCarryFlag),
|
|
||||||
cycles: 4,
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_complement_a_register_data() -> ParseOutput {
|
fn build_complement_a_register_data() -> ParseOutput {
|
||||||
(
|
(Instruction::Misc(MiscInstruction::ComplementARegister), 1)
|
||||||
RunnableInstruction {
|
|
||||||
instruction: Instruction::Misc(MiscInstruction::ComplementARegister),
|
|
||||||
cycles: 4,
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_daa_data() -> ParseOutput {
|
fn build_daa_data() -> ParseOutput {
|
||||||
(
|
(
|
||||||
RunnableInstruction {
|
Instruction::Misc(MiscInstruction::DecimalAdjustAccumulator),
|
||||||
instruction: Instruction::Misc(MiscInstruction::DecimalAdjustAccumulator),
|
|
||||||
cycles: 4,
|
|
||||||
},
|
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,18 @@ pub enum Error {
|
||||||
|
|
||||||
/// `Run` takes a single instruction and runs it on the given processor.
|
/// `Run` takes a single instruction and runs it on the given processor.
|
||||||
trait Run {
|
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.
|
/// `run_instruction` will run the given instruction on the processor.
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[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 {
|
match instruction {
|
||||||
Instruction::EightBitLoad(load_instruction) => load_instruction.run_on(processor),
|
Instruction::EightBitLoad(load_instruction) => load_instruction.run_on(processor),
|
||||||
Instruction::SixteenBitLoad(load_instruction) => load_instruction.run_on(processor),
|
Instruction::SixteenBitLoad(load_instruction) => load_instruction.run_on(processor),
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::{cpu::instructions::arith16::SixteenBitArithmeticInstruction, register};
|
use crate::{cpu::instructions::arith16::SixteenBitArithmeticInstruction, register};
|
||||||
|
|
||||||
use super::{arithutil::CarryingAdd, Run};
|
use super::{arithutil::CarryingAdd, Cycles, Run};
|
||||||
|
|
||||||
impl Run for SixteenBitArithmeticInstruction {
|
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 {
|
match *self {
|
||||||
SixteenBitArithmeticInstruction::IncrementRegister { operand_register } => {
|
SixteenBitArithmeticInstruction::IncrementRegister { operand_register } => {
|
||||||
let register_value = processor.registers.get_16bit_register(operand_register);
|
let register_value = processor.registers.get_16bit_register(operand_register);
|
||||||
|
@ -12,7 +12,7 @@ impl Run for SixteenBitArithmeticInstruction {
|
||||||
.registers
|
.registers
|
||||||
.set_16bit_register(operand_register, incremented_value);
|
.set_16bit_register(operand_register, incremented_value);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
SixteenBitArithmeticInstruction::DecrementRegister { operand_register } => {
|
SixteenBitArithmeticInstruction::DecrementRegister { operand_register } => {
|
||||||
|
@ -22,7 +22,7 @@ impl Run for SixteenBitArithmeticInstruction {
|
||||||
.registers
|
.registers
|
||||||
.set_16bit_register(operand_register, decremented_value);
|
.set_16bit_register(operand_register, decremented_value);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
SixteenBitArithmeticInstruction::AddRegisterToHL { operand_register } => {
|
SixteenBitArithmeticInstruction::AddRegisterToHL { operand_register } => {
|
||||||
|
@ -45,7 +45,7 @@ impl Run for SixteenBitArithmeticInstruction {
|
||||||
.registers
|
.registers
|
||||||
.set_flag_bit(register::Flag::Subtract, 0);
|
.set_flag_bit(register::Flag::Subtract, 0);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(8))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
register,
|
register,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{arithutil::CarryingAdd, Run};
|
use super::{arithutil::CarryingAdd, Cycles, Run};
|
||||||
|
|
||||||
mod binary;
|
mod binary;
|
||||||
mod unary;
|
mod unary;
|
||||||
|
@ -26,7 +26,7 @@ struct OperationFlagOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Run for EightBitArithmeticInstruction {
|
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 {
|
match self.operation {
|
||||||
Operation::Add => binary::run_add(processor, self.operand),
|
Operation::Add => binary::run_add(processor, self.operand),
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ impl Run for EightBitArithmeticInstruction {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Run for AdjustStackPointerInstruction {
|
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
|
let stack_pointer = processor
|
||||||
.registers
|
.registers
|
||||||
.get_single_16bit_register(register::SingleSixteenBit::StackPointer);
|
.get_single_16bit_register(register::SingleSixteenBit::StackPointer);
|
||||||
|
@ -72,7 +72,7 @@ impl Run for AdjustStackPointerInstruction {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(16))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
instructions::arith8::Operand,
|
instructions::arith8::Operand,
|
||||||
run::{
|
run::{
|
||||||
arithutil::{self, CarriedNumber, CarryingAdd, CarryingSub},
|
arithutil::{self, CarriedNumber, CarryingAdd, CarryingSub},
|
||||||
Error,
|
Cycles, Error,
|
||||||
},
|
},
|
||||||
Processor,
|
Processor,
|
||||||
},
|
},
|
||||||
|
@ -12,11 +12,11 @@ use crate::{
|
||||||
|
|
||||||
use super::{OperationFlagOutput, OperationOutput};
|
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)
|
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)
|
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)
|
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)
|
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;
|
let a_value = processor.registers.a;
|
||||||
// A compare is just a sub, preserving the A value, so we can just do a sub
|
// A compare is just a sub, preserving the A value, so we can just do a sub
|
||||||
// and restore the original value
|
// and restore the original value
|
||||||
run_sub(processor, operand)?;
|
let sub_cycles = run_sub(processor, operand)?;
|
||||||
|
|
||||||
processor
|
processor
|
||||||
.registers
|
.registers
|
||||||
.set_single_8bit_register(register::SingleEightBit::A, a_value);
|
.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| {
|
run_operation(processor, operand, |lhs, rhs| {
|
||||||
let total = 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| {
|
run_operation(processor, operand, |lhs, rhs| {
|
||||||
let total = 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| {
|
run_operation(processor, operand, |lhs, rhs| {
|
||||||
let total = 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
|
where
|
||||||
F: FnOnce(u8, u8) -> OperationOutput,
|
F: FnOnce(u8, u8) -> OperationOutput,
|
||||||
{
|
{
|
||||||
let operand_values = gather_operand_values(processor, operand)?;
|
let operand_values = gather_operand_values(processor, operand)?;
|
||||||
run_operation_on_operands(processor, operand_values, operation);
|
run_operation_on_operands(processor, operand_values, operation);
|
||||||
|
|
||||||
Ok(())
|
Ok(cycles_for_operand(operand))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_operation_with_carry<F>(
|
fn run_operation_with_carry<F>(
|
||||||
processor: &mut Processor,
|
processor: &mut Processor,
|
||||||
operand: Operand,
|
operand: Operand,
|
||||||
operation: F,
|
operation: F,
|
||||||
) -> Result<(), Error>
|
) -> Result<Cycles, Error>
|
||||||
where
|
where
|
||||||
F: FnOnce(u8, CarriedNumber<u8>) -> OperationOutput,
|
F: FnOnce(u8, CarriedNumber<u8>) -> OperationOutput,
|
||||||
{
|
{
|
||||||
let operand_values = gather_operands_with_carry(processor, operand)?;
|
let operand_values = gather_operands_with_carry(processor, operand)?;
|
||||||
run_operation_on_operands(processor, operand_values, operation);
|
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)
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
instructions::arith8::Operand,
|
instructions::arith8::Operand,
|
||||||
run::{
|
run::{
|
||||||
arithutil::{CarryingAdd, CarryingSub},
|
arithutil::{CarryingAdd, CarryingSub},
|
||||||
Error,
|
Cycles, Error,
|
||||||
},
|
},
|
||||||
Processor,
|
Processor,
|
||||||
},
|
},
|
||||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
|
|
||||||
use super::{OperationFlagOutput, OperationOutput};
|
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);
|
let current_carry_flag = processor.registers.get_flag_bit(register::Flag::Carry);
|
||||||
run_operation(processor, operand, |value| {
|
run_operation(processor, operand, |value| {
|
||||||
let (result, half_carry, _full_carry) = value.add_with_carry(1);
|
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);
|
let current_carry_flag = processor.registers.get_flag_bit(register::Flag::Carry);
|
||||||
run_operation(processor, operand, |value| {
|
run_operation(processor, operand, |value| {
|
||||||
let (result, half_carry, _full_carry) = value.sub_with_carry(1);
|
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
|
where
|
||||||
F: Fn(u8) -> OperationOutput,
|
F: Fn(u8) -> OperationOutput,
|
||||||
{
|
{
|
||||||
|
@ -56,7 +60,7 @@ where
|
||||||
store_output_value(processor, operand, output.value)?;
|
store_output_value(processor, operand, output.value)?;
|
||||||
super::store_flags(processor, output.flags);
|
super::store_flags(processor, output.flags);
|
||||||
|
|
||||||
Ok(())
|
Ok(cycles_for_operand(operand))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gather_operand_value(processor: &mut Processor, operand: Operand) -> Result<u8, Error> {
|
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"),
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
use super::arithutil::CarryingAdd;
|
use super::arithutil::CarryingAdd;
|
||||||
use super::{Error, Run};
|
use super::{Cycles, Error, Run};
|
||||||
use crate::cpu::{instructions::load16::SixteenBitLoadInstruction, Processor};
|
use crate::cpu::{instructions::load16::SixteenBitLoadInstruction, Processor};
|
||||||
use crate::{memory, register};
|
use crate::{memory, register};
|
||||||
|
|
||||||
impl Run for SixteenBitLoadInstruction {
|
impl Run for SixteenBitLoadInstruction {
|
||||||
// TODO: Fix this
|
// TODO: Fix this
|
||||||
#[allow(clippy::too_many_lines)]
|
#[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 {
|
match *self {
|
||||||
SixteenBitLoadInstruction::LoadImmediateToRegister { dst, value } => {
|
SixteenBitLoadInstruction::LoadImmediateToRegister { dst, value } => {
|
||||||
processor.registers.set_16bit_register(dst, value);
|
processor.registers.set_16bit_register(dst, value);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(12))
|
||||||
}
|
}
|
||||||
|
|
||||||
SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src } => {
|
SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src } => {
|
||||||
let value = processor.registers.get_16bit_register(src);
|
let value = processor.registers.get_16bit_register(src);
|
||||||
processor.registers.set_16bit_register(dst, value);
|
processor.registers.set_16bit_register(dst, value);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
SixteenBitLoadInstruction::LoadEffectiveAddress { dst, offset } => {
|
SixteenBitLoadInstruction::LoadEffectiveAddress { dst, offset } => {
|
||||||
|
@ -43,7 +43,7 @@ impl Run for SixteenBitLoadInstruction {
|
||||||
|
|
||||||
processor.registers.set_combined_register(dst, new_sp);
|
processor.registers.set_combined_register(dst, new_sp);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(12))
|
||||||
}
|
}
|
||||||
|
|
||||||
SixteenBitLoadInstruction::Push { src } => {
|
SixteenBitLoadInstruction::Push { src } => {
|
||||||
|
@ -74,7 +74,7 @@ impl Run for SixteenBitLoadInstruction {
|
||||||
current_sp - 2,
|
current_sp - 2,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(16))
|
||||||
}
|
}
|
||||||
|
|
||||||
SixteenBitLoadInstruction::Pop { dst } => {
|
SixteenBitLoadInstruction::Pop { dst } => {
|
||||||
|
@ -112,7 +112,7 @@ impl Run for SixteenBitLoadInstruction {
|
||||||
current_sp + 2,
|
current_sp + 2,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(12))
|
||||||
}
|
}
|
||||||
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address } => {
|
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address } => {
|
||||||
let current_sp = processor
|
let current_sp = processor
|
||||||
|
@ -126,7 +126,7 @@ impl Run for SixteenBitLoadInstruction {
|
||||||
));
|
));
|
||||||
|
|
||||||
match memory_res {
|
match memory_res {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(Cycles(20)),
|
||||||
Err(memory::Error::GetInvalidAddress(bad_addr)) => {
|
Err(memory::Error::GetInvalidAddress(bad_addr)) => {
|
||||||
Err(Error::InvalidImmediateAddress(bad_addr))
|
Err(Error::InvalidImmediateAddress(bad_addr))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Error, Run};
|
use super::{Cycles, Error, Run};
|
||||||
use crate::{
|
use crate::{
|
||||||
cpu::{instructions::load8::EightBitLoadInstruction, Processor},
|
cpu::{instructions::load8::EightBitLoadInstruction, Processor},
|
||||||
memory, register,
|
memory, register,
|
||||||
|
@ -7,35 +7,45 @@ use crate::{
|
||||||
impl Run for EightBitLoadInstruction {
|
impl Run for EightBitLoadInstruction {
|
||||||
// TODO: Break this up somehow
|
// TODO: Break this up somehow
|
||||||
#[allow(clippy::too_many_lines)]
|
#[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 {
|
match *self {
|
||||||
EightBitLoadInstruction::LoadImmediateToRegister { value, register } => {
|
EightBitLoadInstruction::LoadImmediateToRegister { value, register } => {
|
||||||
processor
|
processor
|
||||||
.registers
|
.registers
|
||||||
.set_single_8bit_register(register, value);
|
.set_single_8bit_register(register, value);
|
||||||
Ok(())
|
|
||||||
|
Ok(Cycles(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
EightBitLoadInstruction::LoadBetweenRegisters { dst, src } => {
|
EightBitLoadInstruction::LoadBetweenRegisters { dst, src } => {
|
||||||
let src_value = processor.registers.get_single_8bit_register(src);
|
let src_value = processor.registers.get_single_8bit_register(src);
|
||||||
processor.registers.set_single_8bit_register(dst, src_value);
|
processor.registers.set_single_8bit_register(dst, src_value);
|
||||||
Ok(())
|
|
||||||
|
Ok(Cycles(4))
|
||||||
}
|
}
|
||||||
|
|
||||||
EightBitLoadInstruction::LoadFromRegisterAddress { src, dst } => {
|
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 } => {
|
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 } => {
|
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 } => {
|
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 } => {
|
EightBitLoadInstruction::LoadnToHLAddress { value } => {
|
||||||
|
@ -43,7 +53,9 @@ impl Run for EightBitLoadInstruction {
|
||||||
.registers
|
.registers
|
||||||
.get_combined_register(register::Combined::HL);
|
.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 {
|
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStart {
|
||||||
|
@ -56,7 +68,8 @@ impl Run for EightBitLoadInstruction {
|
||||||
let src_address =
|
let src_address =
|
||||||
memory::IO_REGISTER_START_ADDRESS + usize::from(src_address_offset);
|
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 {
|
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStart {
|
||||||
|
@ -69,7 +82,9 @@ impl Run for EightBitLoadInstruction {
|
||||||
let dst_address =
|
let dst_address =
|
||||||
memory::IO_REGISTER_START_ADDRESS + usize::from(dst_address_offset);
|
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 } => {
|
EightBitLoadInstruction::LoadFromRegisterAddressThenDec { dst, src } => {
|
||||||
|
@ -80,7 +95,7 @@ impl Run for EightBitLoadInstruction {
|
||||||
.registers
|
.registers
|
||||||
.set_combined_register(src, src_address - 1);
|
.set_combined_register(src, src_address - 1);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
EightBitLoadInstruction::LoadFromRegisterAddressThenInc { dst, src } => {
|
EightBitLoadInstruction::LoadFromRegisterAddressThenInc { dst, src } => {
|
||||||
|
@ -91,7 +106,7 @@ impl Run for EightBitLoadInstruction {
|
||||||
.registers
|
.registers
|
||||||
.set_combined_register(src, src_address + 1);
|
.set_combined_register(src, src_address + 1);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
EightBitLoadInstruction::LoadToRegisterAddressThenDec { dst, src } => {
|
EightBitLoadInstruction::LoadToRegisterAddressThenDec { dst, src } => {
|
||||||
|
@ -102,7 +117,7 @@ impl Run for EightBitLoadInstruction {
|
||||||
.registers
|
.registers
|
||||||
.set_combined_register(dst, dst_address - 1);
|
.set_combined_register(dst, dst_address - 1);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
EightBitLoadInstruction::LoadToRegisterAddressThenInc { dst, src } => {
|
EightBitLoadInstruction::LoadToRegisterAddressThenInc { dst, src } => {
|
||||||
|
@ -113,7 +128,7 @@ impl Run for EightBitLoadInstruction {
|
||||||
.registers
|
.registers
|
||||||
.set_combined_register(dst, dst_address + 1);
|
.set_combined_register(dst, dst_address + 1);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(8))
|
||||||
}
|
}
|
||||||
|
|
||||||
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
|
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
|
||||||
|
@ -121,7 +136,9 @@ impl Run for EightBitLoadInstruction {
|
||||||
offset,
|
offset,
|
||||||
} => {
|
} => {
|
||||||
let dst_address = memory::IO_REGISTER_START_ADDRESS + usize::from(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 {
|
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStartByImmediate {
|
||||||
|
@ -129,7 +146,9 @@ impl Run for EightBitLoadInstruction {
|
||||||
offset,
|
offset,
|
||||||
} => {
|
} => {
|
||||||
let src_address = memory::IO_REGISTER_START_ADDRESS + usize::from(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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,15 @@ use crate::{
|
||||||
register::Registers,
|
register::Registers,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Run;
|
use super::{Cycles, Run};
|
||||||
|
|
||||||
impl Run for MiscInstruction {
|
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 {
|
match *self {
|
||||||
MiscInstruction::SetCarryFlag => {
|
MiscInstruction::SetCarryFlag => {
|
||||||
set_flags_in_carry_bit_instruction(processor, 1);
|
set_flags_in_carry_bit_instruction(processor, 1);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(4))
|
||||||
}
|
}
|
||||||
MiscInstruction::ComplementCarryFlag => {
|
MiscInstruction::ComplementCarryFlag => {
|
||||||
let current_carry_flag = processor.registers.get_flag_bit(register::Flag::Carry);
|
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);
|
set_flags_in_carry_bit_instruction(processor, flipped);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(4))
|
||||||
}
|
}
|
||||||
MiscInstruction::ComplementARegister => {
|
MiscInstruction::ComplementARegister => {
|
||||||
let current_value = processor
|
let current_value = processor
|
||||||
|
@ -36,7 +36,7 @@ impl Run for MiscInstruction {
|
||||||
.registers
|
.registers
|
||||||
.set_flag_bit(register::Flag::Subtract, 1);
|
.set_flag_bit(register::Flag::Subtract, 1);
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(4))
|
||||||
}
|
}
|
||||||
MiscInstruction::DecimalAdjustAccumulator => {
|
MiscInstruction::DecimalAdjustAccumulator => {
|
||||||
let (adjusted_a_value, carry) = get_daa_value(&processor.registers);
|
let (adjusted_a_value, carry) = get_daa_value(&processor.registers);
|
||||||
|
@ -57,7 +57,7 @@ impl Run for MiscInstruction {
|
||||||
.registers
|
.registers
|
||||||
.set_flag_bit(register::Flag::Zero, (adjusted_a_value == 0).into());
|
.set_flag_bit(register::Flag::Zero, (adjusted_a_value == 0).into());
|
||||||
|
|
||||||
Ok(())
|
Ok(Cycles(4))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use ferris_boi::{
|
use ferris_boi::{
|
||||||
cpu::{instructions::RunnableInstruction, Processor},
|
cpu::{instructions::Instruction, Processor},
|
||||||
register,
|
register,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,11 +21,10 @@ fn test_add_hl_to_itself() {
|
||||||
);
|
);
|
||||||
let data = [0x29, 0x02];
|
let data = [0x29, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0x4488,
|
0x4488,
|
||||||
|
@ -60,11 +59,10 @@ fn test_add_hl_to_registers_value(
|
||||||
.set_16bit_register(operand_register, operand_value);
|
.set_16bit_register(operand_register, operand_value);
|
||||||
let data = [opcode, 0x02];
|
let data = [opcode, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected,
|
expected,
|
||||||
|
@ -102,8 +100,7 @@ fn test_add_hl_to_registers_flags(
|
||||||
.set_16bit_register(operand_register, operand_value);
|
.set_16bit_register(operand_register, operand_value);
|
||||||
let data = [opcode, 0x02];
|
let data = [opcode, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
// Set all the register to the opposite we expect to ensure they all get set
|
// 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),
|
(0, 0, expected_flags.half_carry, expected_flags.carry),
|
||||||
);
|
);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -150,11 +147,10 @@ fn test_increment(
|
||||||
.expect("Failed to set flag bits");
|
.expect("Failed to set flag bits");
|
||||||
let data = [opcode, 0x02];
|
let data = [opcode, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected,
|
expected,
|
||||||
|
@ -191,11 +187,10 @@ fn test_decrement(
|
||||||
.expect("Failed to set flag bits");
|
.expect("Failed to set flag bits");
|
||||||
let data = [opcode, 0x02];
|
let data = [opcode, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected,
|
expected,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use ferris_boi::{
|
use ferris_boi::{
|
||||||
cpu::{instructions::RunnableInstruction, Processor},
|
cpu::{instructions::Instruction, Processor},
|
||||||
register,
|
register,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,11 +25,10 @@ fn test_add_a_to_itself() {
|
||||||
processor.registers.a = 10;
|
processor.registers.a = 10;
|
||||||
let data = [0x87, 0x02];
|
let data = [0x87, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(20, processor.registers.a);
|
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);
|
processor.registers.set_single_8bit_register(src, 20);
|
||||||
let data = [opcode, 0x02];
|
let data = [opcode, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(30, processor.registers.a);
|
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);
|
processor.registers.set_single_8bit_register(src, src_value);
|
||||||
let data = [opcode, 0x02];
|
let data = [opcode, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -123,11 +120,10 @@ fn test_add_hl_addr_to_a_value() {
|
||||||
|
|
||||||
let data = [0x86, 0x02];
|
let data = [0x86, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0x46, processor.registers.a);
|
assert_eq!(0x46, processor.registers.a);
|
||||||
}
|
}
|
||||||
|
@ -166,11 +162,10 @@ fn test_add_hl_addr_to_a_flags(
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = [0x86, 0x01];
|
let data = [0x86, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -187,11 +182,10 @@ fn test_add_immediate_to_a_value() {
|
||||||
processor.registers.a = 50;
|
processor.registers.a = 50;
|
||||||
|
|
||||||
let data = [0xC6, 0x13, 0x01];
|
let data = [0xC6, 0x13, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(69, processor.registers.a);
|
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 data = [0xC6, n, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -260,10 +253,9 @@ fn test_add_register_with_carry_to_a_value(
|
||||||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
|
|
||||||
let data = [opcode, 0x01];
|
let data = [opcode, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(expected_value, processor.registers.a);
|
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);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
|
|
||||||
let data = [opcode, 0x01];
|
let data = [opcode, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
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);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
let data = [0x8F, 0x01];
|
let data = [0x8F, 0x01];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(processor.registers.a, expected_value);
|
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);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
let data = [0x8F, 0x01];
|
let data = [0x8F, 0x01];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -410,10 +399,9 @@ fn test_add_immediate_with_carry_to_a_value(
|
||||||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
let data = [0xCE, operand, 0x01];
|
let data = [0xCE, operand, 0x01];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(processor.registers.a, expected_value);
|
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);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
let data = [0xCE, operand, 0x01];
|
let data = [0xCE, operand, 0x01];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
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 data = [0x8E, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(expected, processor.registers.a);
|
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 data = [0x8E, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -567,11 +552,10 @@ fn test_sub_register_from_a_value(
|
||||||
|
|
||||||
let data = [opcode, 0x02];
|
let data = [opcode, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(processor.registers.a, expected);
|
assert_eq!(processor.registers.a, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,11 +597,10 @@ fn test_sub_register_from_a_flags(
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = [opcode, 0x02];
|
let data = [opcode, 0x02];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -634,14 +617,13 @@ fn test_sub_a_from_itself() {
|
||||||
processor.registers.a = 0xFF;
|
processor.registers.a = 0xFF;
|
||||||
|
|
||||||
let data = [0x97, 0x02];
|
let data = [0x97, 0x02];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
// Set all the register to the opposite we expect to ensure they all get set
|
// 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));
|
testutil::set_opposite_of_expected_flags(&mut processor, (0, 0, 1, 1));
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -681,11 +663,10 @@ fn test_sub_register_with_carry_from_a_value(
|
||||||
|
|
||||||
let data = [opcode, 0x02];
|
let data = [opcode, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(processor.registers.a, expected);
|
assert_eq!(processor.registers.a, expected);
|
||||||
}
|
}
|
||||||
#[test_matrix(
|
#[test_matrix(
|
||||||
|
@ -739,10 +720,9 @@ fn test_sub_register_from_carry_from_a_flags(
|
||||||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
|
|
||||||
let data = [opcode, 0x01];
|
let data = [opcode, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -759,11 +739,10 @@ fn test_subtract_immediate_from_a_value() {
|
||||||
processor.registers.a = 0xFF;
|
processor.registers.a = 0xFF;
|
||||||
let data = [0xD6, 0x0F, 0x02];
|
let data = [0xD6, 0x0F, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(processor.registers.a, 0xF0);
|
assert_eq!(processor.registers.a, 0xF0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,10 +770,9 @@ fn test_sub_immediate_from_a_flags(
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = [0xD6, operand, 0x01];
|
let data = [0xD6, operand, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -821,11 +799,10 @@ fn test_sub_immediate_with_carry_from_a_value(
|
||||||
|
|
||||||
let data = [0xDE, operand, 0x02];
|
let data = [0xDE, operand, 0x02];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x02]);
|
assert_eq!(extra_data, &[0x02]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(processor.registers.a, expected);
|
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);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
|
|
||||||
let data = [0xDE, operand, 0x01];
|
let data = [0xDE, operand, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
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);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
|
|
||||||
let data = [0x9F, 0x01];
|
let data = [0x9F, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(expected, processor.registers.a);
|
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);
|
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||||
|
|
||||||
let data = [0x9F, 0x01];
|
let data = [0x9F, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -948,10 +922,9 @@ fn test_sub_hl_addr_from_a_value() {
|
||||||
.set_combined_register(register::Combined::HL, 0xABCD);
|
.set_combined_register(register::Combined::HL, 0xABCD);
|
||||||
|
|
||||||
let data = [0x96, 0x01];
|
let data = [0x96, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0x11, processor.registers.a);
|
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);
|
.set_combined_register(register::Combined::HL, 0xABCD);
|
||||||
|
|
||||||
let data = [0x96, 0x01];
|
let data = [0x96, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
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);
|
.set_combined_register(register::Combined::HL, 0xABCD);
|
||||||
|
|
||||||
let data = [0x9E, 0x01];
|
let data = [0x9E, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(expected_value, processor.registers.a);
|
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);
|
.set_combined_register(register::Combined::HL, 0xABCD);
|
||||||
|
|
||||||
let data = [0x9E, 0x01];
|
let data = [0x9E, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1103,10 +1073,9 @@ fn test_and_single_register_with_a_value(
|
||||||
.set_single_8bit_register(operand_register, operand);
|
.set_single_8bit_register(operand_register, operand);
|
||||||
|
|
||||||
let data = [opcode, 0x01];
|
let data = [opcode, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(expected_value, processor.registers.a);
|
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);
|
.set_single_8bit_register(operand_register, operand);
|
||||||
|
|
||||||
let data = [opcode, 0x01];
|
let data = [opcode, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1157,10 +1125,9 @@ fn test_and_a_with_itself_value() {
|
||||||
processor.registers.a = 0xAB;
|
processor.registers.a = 0xAB;
|
||||||
|
|
||||||
let data = [0xA7, 0x01];
|
let data = [0xA7, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0xAB, processor.registers.a);
|
assert_eq!(0xAB, processor.registers.a);
|
||||||
}
|
}
|
||||||
|
@ -1174,10 +1141,9 @@ fn test_and_a_with_itself_flags() {
|
||||||
processor.registers.a = 0xAB;
|
processor.registers.a = 0xAB;
|
||||||
|
|
||||||
let data = [0xA7, 0x01];
|
let data = [0xA7, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1201,10 +1167,9 @@ fn test_and_hl_value_with_a_value() {
|
||||||
.expect("failed to set value");
|
.expect("failed to set value");
|
||||||
|
|
||||||
let data = [0xA6, 0x01];
|
let data = [0xA6, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0xA0, processor.registers.a);
|
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));
|
testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 1, 0));
|
||||||
|
|
||||||
let data = [0xA6, 0x01];
|
let data = [0xA6, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1246,10 +1210,9 @@ fn test_and_immediate_with_a_value() {
|
||||||
processor.registers.a = 0xAB;
|
processor.registers.a = 0xAB;
|
||||||
|
|
||||||
let data = [0xE6, 0x0F, 0x01];
|
let data = [0xE6, 0x0F, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0x0B, processor.registers.a);
|
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));
|
testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 1, 0));
|
||||||
|
|
||||||
let data = [0xE6, operand, 0x01];
|
let data = [0xE6, operand, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1300,10 +1262,9 @@ fn test_xor_register_with_a_value(
|
||||||
.set_single_8bit_register(operand_register, operand);
|
.set_single_8bit_register(operand_register, operand);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(expected_value, processor.registers.a);
|
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);
|
.set_single_8bit_register(operand_register, operand);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1356,10 +1316,9 @@ fn test_xor_register_a_with_itself_value() {
|
||||||
processor.registers.a = 0x45;
|
processor.registers.a = 0x45;
|
||||||
|
|
||||||
let data = [0xAF, 0x01];
|
let data = [0xAF, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0, processor.registers.a);
|
assert_eq!(0, processor.registers.a);
|
||||||
}
|
}
|
||||||
|
@ -1372,10 +1331,9 @@ fn test_xor_register_a_with_itself_flags() {
|
||||||
processor.registers.a = 0x45;
|
processor.registers.a = 0x45;
|
||||||
|
|
||||||
let data = [0xAF, 0x01];
|
let data = [0xAF, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1402,10 +1360,9 @@ fn test_xor_hl_value_with_a_value() {
|
||||||
.expect("failed to set memory value");
|
.expect("failed to set memory value");
|
||||||
|
|
||||||
let data = [0xAE, 0x03];
|
let data = [0xAE, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0x55, processor.registers.a);
|
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");
|
.expect("failed to set memory value");
|
||||||
|
|
||||||
let data = [0xAE, 0x03];
|
let data = [0xAE, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1450,10 +1406,9 @@ fn test_xor_immediate_value_with_a_value() {
|
||||||
.set_single_8bit_register(register::SingleEightBit::A, 0x22);
|
.set_single_8bit_register(register::SingleEightBit::A, 0x22);
|
||||||
|
|
||||||
let data = [0xEE, 0xEE, 0x03];
|
let data = [0xEE, 0xEE, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0xCC, processor.registers.a);
|
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);
|
.set_single_8bit_register(register::SingleEightBit::A, a_value);
|
||||||
|
|
||||||
let data = [0xEE, operand, 0x03];
|
let data = [0xEE, operand, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1509,10 +1463,9 @@ fn test_or_register_with_a_value(
|
||||||
.set_single_8bit_register(operand_register, operand);
|
.set_single_8bit_register(operand_register, operand);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(expected_value, processor.registers.a);
|
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);
|
.set_single_8bit_register(operand_register, operand);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1565,10 +1517,9 @@ fn test_or_register_a_with_itself_value() {
|
||||||
processor.registers.a = 0x45;
|
processor.registers.a = 0x45;
|
||||||
|
|
||||||
let data = [0xB7, 0x01];
|
let data = [0xB7, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0x45, processor.registers.a);
|
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;
|
processor.registers.a = operand;
|
||||||
|
|
||||||
let data = [0xB7, 0x01];
|
let data = [0xB7, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1612,10 +1562,9 @@ fn test_or_hl_value_with_a_value() {
|
||||||
.expect("failed to set memory value");
|
.expect("failed to set memory value");
|
||||||
|
|
||||||
let data = [0xB6, 0x03];
|
let data = [0xB6, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0xBB, processor.registers.a);
|
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");
|
.expect("failed to set memory value");
|
||||||
|
|
||||||
let data = [0xB7, 0x01];
|
let data = [0xB7, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1661,10 +1609,9 @@ fn test_or_immediate_value_with_a_value() {
|
||||||
.set_single_8bit_register(register::SingleEightBit::A, 0x33);
|
.set_single_8bit_register(register::SingleEightBit::A, 0x33);
|
||||||
|
|
||||||
let data = [0xF6, 0xAA, 0x03];
|
let data = [0xF6, 0xAA, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0xBB, processor.registers.a);
|
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);
|
.set_single_8bit_register(register::SingleEightBit::A, a_value);
|
||||||
|
|
||||||
let data = [0xF6, operand, 0x03];
|
let data = [0xF6, operand, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1710,10 +1656,9 @@ fn test_compare_register_instructions_do_not_modify_register_values(
|
||||||
processor.registers.set_single_8bit_register(register, 0x22);
|
processor.registers.set_single_8bit_register(register, 0x22);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0xFF,
|
0xFF,
|
||||||
|
@ -1733,10 +1678,9 @@ fn test_compare_register_with_itself_does_not_modify_value() {
|
||||||
.set_single_8bit_register(register::SingleEightBit::A, 0xFF);
|
.set_single_8bit_register(register::SingleEightBit::A, 0xFF);
|
||||||
|
|
||||||
let data = [0xBF, 0x03];
|
let data = [0xBF, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0xFF,
|
0xFF,
|
||||||
|
@ -1767,10 +1711,9 @@ fn test_comparing_equal_values_between_registers_sets_zero_flag(
|
||||||
processor.registers.set_single_8bit_register(register, 0xFF);
|
processor.registers.set_single_8bit_register(register, 0xFF);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0xFF,
|
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);
|
processor.registers.set_single_8bit_register(register, 0x01);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
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);
|
processor.registers.set_single_8bit_register(register, 0x1F);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
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);
|
processor.registers.set_single_8bit_register(register, 0xFF);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
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);
|
processor.registers.set_single_8bit_register(register, 0x2F);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -1940,10 +1879,9 @@ fn test_comparing_hl_value_to_a_does_not_change_value() {
|
||||||
.expect("failde to set value");
|
.expect("failde to set value");
|
||||||
|
|
||||||
let data = [0xBE, 0x03];
|
let data = [0xBE, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0xFF,
|
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 data = [0xBE, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -2006,10 +1943,9 @@ fn test_comparing_immediate_value_to_a_does_not_change_value() {
|
||||||
.set_single_8bit_register(register::SingleEightBit::A, 0xFF);
|
.set_single_8bit_register(register::SingleEightBit::A, 0xFF);
|
||||||
|
|
||||||
let data = [0xFE, 0xBB, 0x03];
|
let data = [0xFE, 0xBB, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0xFF,
|
0xFF,
|
||||||
|
@ -2046,10 +1982,9 @@ fn test_comparing_immediate_value_to_a(
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = [0xFE, operand, 0x03];
|
let data = [0xFE, operand, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -2102,10 +2037,9 @@ fn test_increment_decrement_single_register_value(
|
||||||
.set_single_8bit_register(register, initial_value);
|
.set_single_8bit_register(register, initial_value);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected_value,
|
expected_value,
|
||||||
|
@ -2168,10 +2102,9 @@ fn test_increment_decrement_single_register_flags(
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -2198,10 +2131,9 @@ fn test_increment_decrement_hl_value(opcode: u8, initial_value: u8, expected_val
|
||||||
.expect("failed to set memory value");
|
.expect("failed to set memory value");
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected_value,
|
expected_value,
|
||||||
|
@ -2246,10 +2178,9 @@ fn test_increment_decrement_hl_flags(
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
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 twos_comp_adjustment = adjustment.to_be_bytes()[0];
|
||||||
let data = [0xE8, twos_comp_adjustment, 0x03];
|
let data = [0xE8, twos_comp_adjustment, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(expected_sp, processor.registers.stack_pointer);
|
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 twos_comp_adjustment = adjustment.to_be_bytes()[0];
|
||||||
let data = [0xE8, twos_comp_adjustment, 0x03];
|
let data = [0xE8, twos_comp_adjustment, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use ferris_boi::{
|
use ferris_boi::{
|
||||||
cpu::{instructions::RunnableInstruction, Processor},
|
cpu::{instructions::Instruction, Processor},
|
||||||
register,
|
register,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,11 +21,10 @@ fn test_load_to_register_address_then_do_arithmetic(
|
||||||
processor.registers.a = 10;
|
processor.registers.a = 10;
|
||||||
|
|
||||||
let data = [opcode, 0x00];
|
let data = [opcode, 0x00];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
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!(10, processor.memory.get(hl_value_before.into()).unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hl_value_after,
|
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 !..
|
// l05c0: ld hl,0ff02h ; 05c0 21 02 ff !..
|
||||||
let data = [opcode, 0x34, 0x12, 0x05];
|
let data = [opcode, 0x34, 0x12, 0x05];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x05]);
|
assert_eq!(extra_data, &[0x05]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0x1234,
|
0x1234,
|
||||||
|
@ -73,11 +71,10 @@ fn test_load_from_hl_to_sp() {
|
||||||
.set_combined_register(register::Combined::HL, 0x1234);
|
.set_combined_register(register::Combined::HL, 0x1234);
|
||||||
let data = [0xF9, 0x00];
|
let data = [0xF9, 0x00];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0x1234, processor.registers.stack_pointer);
|
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 data = [0xF8, unsigned_value, 0x00];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected_sp,
|
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 data = [0xF8, unsigned_value, 0x00];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -166,11 +161,10 @@ fn test_stack_push(opcode: u8, src: register::Combined) {
|
||||||
processor.registers.stack_pointer = 0xFFFE;
|
processor.registers.stack_pointer = 0xFFFE;
|
||||||
let data = [opcode, 0x01];
|
let data = [opcode, 0x01];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
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)
|
// 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
|
// 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;
|
processor.registers.stack_pointer = 0xFFFE;
|
||||||
let data = [0xF5, 0x01];
|
let data = [0xF5, 0x01];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
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)
|
// 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
|
// 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");
|
.expect("failed to set values in memory");
|
||||||
let data = [opcode, 0x01];
|
let data = [opcode, 0x01];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0x1234, processor.registers.get_combined_register(dst));
|
assert_eq!(0x1234, processor.registers.get_combined_register(dst));
|
||||||
assert_eq!(0xFFF0 + 2, processor.registers.stack_pointer);
|
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");
|
.expect("failed to set values in memory");
|
||||||
let data = [0xF1, 0x01];
|
let data = [0xF1, 0x01];
|
||||||
|
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x01]);
|
assert_eq!(extra_data, &[0x01]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0x1230,
|
0x1230,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use ferris_boi::{
|
use ferris_boi::{
|
||||||
cpu::{instructions::RunnableInstruction, Processor},
|
cpu::{instructions::Instruction, Processor},
|
||||||
register,
|
register,
|
||||||
};
|
};
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
@ -65,13 +65,12 @@ fn test_load_register(
|
||||||
.set_single_8bit_register(src_register, 0x45);
|
.set_single_8bit_register(src_register, 0x45);
|
||||||
|
|
||||||
let data = [load_opcode, 0x00];
|
let data = [load_opcode, 0x00];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
// assert our extra data after the instruction is returned
|
// assert our extra data after the instruction is returned
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0x45,
|
0x45,
|
||||||
processor.registers.get_single_8bit_register(dst_register)
|
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) {
|
fn test_load_immediate(load_opcode: u8, expected_register: register::SingleEightBit) {
|
||||||
let mut processor = Processor::default();
|
let mut processor = Processor::default();
|
||||||
let data = [load_opcode, 0x23, 0x00, 0x01];
|
let data = [load_opcode, 0x23, 0x00, 0x01];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
// assert our extra data after the instruction is returned
|
// assert our extra data after the instruction is returned
|
||||||
// this data is just garbage; no idea if it's a valid instruction
|
// this data is just garbage; no idea if it's a valid instruction
|
||||||
assert_eq!(extra_data, &[0x00, 0x01]);
|
assert_eq!(extra_data, &[0x00, 0x01]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
0x23,
|
0x23,
|
||||||
processor
|
processor
|
||||||
|
@ -127,12 +125,11 @@ fn test_load_from_memory(
|
||||||
.set_combined_register(expected_deref_register, 0xCCDD);
|
.set_combined_register(expected_deref_register, 0xCCDD);
|
||||||
|
|
||||||
let data = [opcode, 0x10, 0x20];
|
let data = [opcode, 0x10, 0x20];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse isntruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse isntruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x10, 0x20]);
|
assert_eq!(extra_data, &[0x10, 0x20]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
105,
|
105,
|
||||||
processor
|
processor
|
||||||
|
@ -168,12 +165,11 @@ fn test_load_to_memory(
|
||||||
.set_combined_register(expected_deref_register, 0xCCCC);
|
.set_combined_register(expected_deref_register, 0xCCCC);
|
||||||
|
|
||||||
let data = [opcode, 0x10, 0x20];
|
let data = [opcode, 0x10, 0x20];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x10, 0x20]);
|
assert_eq!(extra_data, &[0x10, 0x20]);
|
||||||
|
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(0xCC, processor.memory.get(0xCCCC).unwrap());
|
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);
|
.set_combined_register(register::Combined::HL, 0xCCDE);
|
||||||
|
|
||||||
let data = [0x36, 0x1D, 0x00];
|
let data = [0x36, 0x1D, 0x00];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(0x1D, processor.memory.get(0xCCDE).unwrap());
|
assert_eq!(0x1D, processor.memory.get(0xCCDE).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,11 +197,10 @@ fn test_load_from_immediate_address() {
|
||||||
.expect("failed to set memory value");
|
.expect("failed to set memory value");
|
||||||
|
|
||||||
let data = [0xFA, 0xDE, 0xCC, 0x00];
|
let data = [0xFA, 0xDE, 0xCC, 0x00];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(105, processor.registers.a);
|
assert_eq!(105, processor.registers.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,11 +209,10 @@ fn test_load_to_immadiate_address() {
|
||||||
let mut processor = Processor::default();
|
let mut processor = Processor::default();
|
||||||
processor.registers.a = 105;
|
processor.registers.a = 105;
|
||||||
let data = [0xEA, 0xDE, 0xCC, 0x00];
|
let data = [0xEA, 0xDE, 0xCC, 0x00];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(105, processor.memory.get(0xCCDE).unwrap());
|
assert_eq!(105, processor.memory.get(0xCCDE).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,11 +226,10 @@ fn test_load_from_io_register_zone() {
|
||||||
processor.registers.c = 0x64;
|
processor.registers.c = 0x64;
|
||||||
|
|
||||||
let data = [0xF2, 0x00];
|
let data = [0xF2, 0x00];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(10, processor.registers.a);
|
assert_eq!(10, processor.registers.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,11 +240,10 @@ fn test_load_to_io_register_zone() {
|
||||||
processor.registers.a = 10;
|
processor.registers.a = 10;
|
||||||
|
|
||||||
let data = [0xE2, 0x00];
|
let data = [0xE2, 0x00];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(10, processor.memory.get(0xFF64).unwrap());
|
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");
|
.expect("failed to set memory value");
|
||||||
|
|
||||||
let data = [opcode, 0x00];
|
let data = [opcode, 0x00];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x00]);
|
assert_eq!(extra_data, &[0x00]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
assert_eq!(10, processor.registers.a);
|
assert_eq!(10, processor.registers.a);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hl_value_after,
|
hl_value_after,
|
||||||
|
@ -293,11 +283,10 @@ fn test_load_to_io_register_zone_by_immediate() {
|
||||||
processor.registers.a = 0xAF;
|
processor.registers.a = 0xAF;
|
||||||
|
|
||||||
let data = [0xE0, 0x05, 0x06];
|
let data = [0xE0, 0x05, 0x06];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x06]);
|
assert_eq!(extra_data, &[0x06]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0xAF, processor.memory.get(0xFF05).unwrap());
|
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");
|
.expect("failed to set memory value");
|
||||||
|
|
||||||
let data = [0xF0, 0x05, 0x06];
|
let data = [0xF0, 0x05, 0x06];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x06]);
|
assert_eq!(extra_data, &[0x06]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0xAF, processor.registers.a);
|
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;
|
processor.registers.stack_pointer = 0xABCD;
|
||||||
|
|
||||||
let data = [0x08, 0xAA, 0xFF, 0x06];
|
let data = [0x08, 0xAA, 0xFF, 0x06];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x06]);
|
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 bottom_stored_value = processor.memory.get_from(0xFFAA).unwrap().get();
|
||||||
let top_stored_value = processor.memory.get_from(0xFFAB).unwrap().get();
|
let top_stored_value = processor.memory.get_from(0xFFAB).unwrap().get();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::testutil::{self, assert_flags_eq};
|
use crate::testutil::{self, assert_flags_eq};
|
||||||
use ferris_boi::{
|
use ferris_boi::{
|
||||||
cpu::{instructions::RunnableInstruction, Processor},
|
cpu::{instructions::Instruction, Processor},
|
||||||
register,
|
register,
|
||||||
};
|
};
|
||||||
use test_case::test_case;
|
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);
|
.set_flag_bit(register::Flag::Carry, starting_value);
|
||||||
|
|
||||||
let data = [0x37, 0x03];
|
let data = [0x37, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
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);
|
let new_carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
|
||||||
assert_eq!(1, new_carry_bit);
|
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);
|
.set_flag_bit(register::Flag::Carry, starting_value);
|
||||||
|
|
||||||
let data = [0x3F, 0x03];
|
let data = [0x3F, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
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);
|
let new_carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
|
||||||
assert_eq!(expected_value, new_carry_bit);
|
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));
|
testutil::set_opposite_of_expected_flags(&mut processor, (0, 0, 0, 1));
|
||||||
|
|
||||||
let data = [opcode, 0x03];
|
let data = [opcode, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -84,11 +81,10 @@ fn test_complement_a_register_value() {
|
||||||
processor.registers.a = 0xF0;
|
processor.registers.a = 0xF0;
|
||||||
|
|
||||||
let data = [0x2F, 0x03];
|
let data = [0x2F, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(0x0F, processor.registers.a);
|
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));
|
testutil::set_opposite_of_expected_flags(&mut processor, (0, 1, 1, 0));
|
||||||
|
|
||||||
let data = [0x2F, 0x03];
|
let data = [0x2F, 0x03];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x03]);
|
assert_eq!(extra_data, &[0x03]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
testutil::assert_flags_eq!(
|
testutil::assert_flags_eq!(
|
||||||
processor,
|
processor,
|
||||||
|
@ -150,11 +145,10 @@ fn test_daa(
|
||||||
.set_flag_bit(register::Flag::Zero, (!expected_flags.zero).into());
|
.set_flag_bit(register::Flag::Zero, (!expected_flags.zero).into());
|
||||||
|
|
||||||
let data = [0x27, 0x06];
|
let data = [0x27, 0x06];
|
||||||
let (ins, extra_data) =
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
|
||||||
|
|
||||||
assert_eq!(extra_data, &[0x06]);
|
assert_eq!(extra_data, &[0x06]);
|
||||||
processor.run_instruction(&ins);
|
processor.run_instruction(ins);
|
||||||
|
|
||||||
assert_eq!(expected_a_value, processor.registers.a);
|
assert_eq!(expected_a_value, processor.registers.a);
|
||||||
assert_flags_eq!(
|
assert_flags_eq!(
|
||||||
|
|
Loading…
Reference in New Issue