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 crate::{
|
||||
|
@ -32,7 +32,7 @@ impl Processor {
|
|||
let (instruction, bytes_read) =
|
||||
parse::next_instruction(&memory_view).expect("invalid instruction");
|
||||
|
||||
self.run_instruction(&instruction);
|
||||
self.run_instruction(instruction);
|
||||
|
||||
let (next_pc, _carry) = pc.overflowing_add(bytes_read);
|
||||
self.registers.program_counter = next_pc;
|
||||
|
@ -42,13 +42,13 @@ impl Processor {
|
|||
///
|
||||
/// # Panics
|
||||
/// Panics if an internal error occurred within the CPU. These are always bugs.
|
||||
pub fn run_instruction(&mut self, instruction: &RunnableInstruction) {
|
||||
let run_res = run::run_instruction(self, instruction.instruction);
|
||||
pub fn run_instruction(&mut self, instruction: Instruction) {
|
||||
let run_res = run::run_instruction(self, instruction);
|
||||
if let Err(err) = run_res {
|
||||
panic!("Fatal CPU error occured: {err}")
|
||||
}
|
||||
|
||||
self.num_cycles += u128::from(instruction.cycles);
|
||||
self.num_cycles += u128::from(run_res.unwrap().0);
|
||||
}
|
||||
|
||||
fn load_from_register_to_register_address(
|
||||
|
|
|
@ -22,14 +22,7 @@ pub enum Instruction {
|
|||
Misc(misc::MiscInstruction),
|
||||
}
|
||||
|
||||
/// `RunnableInstruction` is an instruction that can run on the processor, and has any metadata needed to do so
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RunnableInstruction {
|
||||
pub(super) instruction: Instruction,
|
||||
pub(super) cycles: u8,
|
||||
}
|
||||
|
||||
impl RunnableInstruction {
|
||||
impl Instruction {
|
||||
/// `from_data` will produce an instruction from the given data and return the data after
|
||||
/// processing that operation.
|
||||
///
|
||||
|
@ -37,7 +30,7 @@ impl RunnableInstruction {
|
|||
///
|
||||
/// # Errors
|
||||
/// Returns an error if the instruction couldn't be parsed.
|
||||
pub fn from_data(data: &[u8]) -> Result<(RunnableInstruction, &[u8]), Error> {
|
||||
pub fn from_data(data: &[u8]) -> Result<(Self, &[u8]), Error> {
|
||||
parse::next_instruction(&View::new_from_data(data, 0))
|
||||
.map(|(ins, offset)| (ins, &data[offset.into()..]))
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::memory::View;
|
||||
|
||||
use super::instructions::RunnableInstruction;
|
||||
use super::instructions::Instruction;
|
||||
use thiserror::Error;
|
||||
|
||||
mod arith16;
|
||||
|
@ -22,7 +22,7 @@ pub enum Error {
|
|||
}
|
||||
|
||||
/// `ParseResult` is the result of a Parse operation, which includes the parsed instruction and the number of bytes read.
|
||||
pub(super) type ParseOutput = (RunnableInstruction, u16);
|
||||
pub(super) type ParseOutput = (Instruction, u16);
|
||||
pub(super) type ParseResult = Result<ParseOutput, Error>;
|
||||
|
||||
/// `OpcodeParser` takes input data, parses out an opcode (and its associated arguments) if it can, and returns
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
cpu::{
|
||||
instructions::arith16::SixteenBitArithmeticInstruction,
|
||||
instructions::Instruction,
|
||||
instructions::{arith16::SixteenBitArithmeticInstruction, RunnableInstruction},
|
||||
parse::{self, Error, OpcodeParser, ParseResult},
|
||||
register::{Combined, SingleSixteenBit, SixteenBit},
|
||||
},
|
||||
|
@ -49,36 +49,27 @@ impl OpcodeParser for Parser {
|
|||
|
||||
fn build_add_hl_to_register_data(operand_register: SixteenBit) -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::SixteenBitArithmetic(
|
||||
SixteenBitArithmeticInstruction::AddRegisterToHL { operand_register },
|
||||
),
|
||||
cycles: 8,
|
||||
},
|
||||
Instruction::SixteenBitArithmetic(SixteenBitArithmeticInstruction::AddRegisterToHL {
|
||||
operand_register,
|
||||
}),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
||||
fn build_inc_register_data(operand_register: SixteenBit) -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::SixteenBitArithmetic(
|
||||
SixteenBitArithmeticInstruction::IncrementRegister { operand_register },
|
||||
),
|
||||
cycles: 8,
|
||||
},
|
||||
Instruction::SixteenBitArithmetic(SixteenBitArithmeticInstruction::IncrementRegister {
|
||||
operand_register,
|
||||
}),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
||||
fn build_dec_register_data(operand_register: SixteenBit) -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::SixteenBitArithmetic(
|
||||
SixteenBitArithmeticInstruction::DecrementRegister { operand_register },
|
||||
),
|
||||
cycles: 8,
|
||||
},
|
||||
Instruction::SixteenBitArithmetic(SixteenBitArithmeticInstruction::DecrementRegister {
|
||||
operand_register,
|
||||
}),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
arith8::{
|
||||
AdjustStackPointerInstruction, EightBitArithmeticInstruction, Operand, Operation,
|
||||
},
|
||||
Instruction, RunnableInstruction,
|
||||
Instruction,
|
||||
},
|
||||
memory::{GetViewTuple, View},
|
||||
register,
|
||||
|
@ -35,28 +35,12 @@ fn parse_eight_bit_arithmetic_instruction(data: &View) -> super::ParseResult {
|
|||
let operation = operation_for_opcode(opcode)?;
|
||||
let operand = operand_for_opcode(opcode)?;
|
||||
|
||||
let parse_data = match (operation, operand) {
|
||||
(_operation, OpcodeOperand::SingleRegister(register)) => {
|
||||
let parse_data = match operand {
|
||||
OpcodeOperand::SingleRegister(register) => {
|
||||
build_instruction_between_register_and_a_data(operation, register)
|
||||
}
|
||||
(Operation::Inc | Operation::Dec, OpcodeOperand::HLAddressValue) => {
|
||||
let (runnable_ins, bytes_read) =
|
||||
build_instruction_between_hl_value_and_a_data(operation);
|
||||
// This is an exception to the other arithmetic instructions
|
||||
(
|
||||
RunnableInstruction {
|
||||
cycles: 12,
|
||||
..runnable_ins
|
||||
},
|
||||
bytes_read,
|
||||
)
|
||||
}
|
||||
(_operation, OpcodeOperand::HLAddressValue) => {
|
||||
build_instruction_between_hl_value_and_a_data(operation)
|
||||
}
|
||||
(_operation, OpcodeOperand::Immediate) => {
|
||||
build_instruction_between_immediate_and_a_data(operation, data)
|
||||
}
|
||||
OpcodeOperand::HLAddressValue => build_instruction_between_hl_value_and_a_data(operation),
|
||||
OpcodeOperand::Immediate => build_instruction_between_immediate_and_a_data(operation, data),
|
||||
};
|
||||
|
||||
Ok(parse_data)
|
||||
|
@ -157,13 +141,7 @@ fn build_instruction_between_register_and_a_data(
|
|||
operation,
|
||||
};
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitArithmetic(instruction),
|
||||
cycles: 4,
|
||||
},
|
||||
1,
|
||||
)
|
||||
(Instruction::EightBitArithmetic(instruction), 1)
|
||||
}
|
||||
|
||||
fn build_instruction_between_hl_value_and_a_data(operation: Operation) -> ParseOutput {
|
||||
|
@ -172,13 +150,7 @@ fn build_instruction_between_hl_value_and_a_data(operation: Operation) -> ParseO
|
|||
operation,
|
||||
};
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitArithmetic(instruction),
|
||||
cycles: 8,
|
||||
},
|
||||
1,
|
||||
)
|
||||
(Instruction::EightBitArithmetic(instruction), 1)
|
||||
}
|
||||
|
||||
fn build_instruction_between_immediate_and_a_data(
|
||||
|
@ -192,13 +164,7 @@ fn build_instruction_between_immediate_and_a_data(
|
|||
operation,
|
||||
};
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitArithmetic(instruction),
|
||||
cycles: 8,
|
||||
},
|
||||
2,
|
||||
)
|
||||
(Instruction::EightBitArithmetic(instruction), 2)
|
||||
}
|
||||
|
||||
fn build_stack_pointer_adjust_data(data: &View) -> ParseOutput {
|
||||
|
@ -207,13 +173,7 @@ fn build_stack_pointer_adjust_data(data: &View) -> ParseOutput {
|
|||
operand: i8::from_be_bytes([n]),
|
||||
};
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::StackPointerAdjust(instruction),
|
||||
cycles: 16,
|
||||
},
|
||||
2,
|
||||
)
|
||||
(Instruction::StackPointerAdjust(instruction), 2)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
|
||||
use crate::cpu::parse::ParseOutput;
|
||||
use crate::cpu::{
|
||||
instructions::{Instruction, RunnableInstruction},
|
||||
instructions::Instruction,
|
||||
parse::{self, Error, OpcodeParser, ParseResult},
|
||||
};
|
||||
use crate::memory::{GetViewTuple, View};
|
||||
|
@ -44,12 +44,10 @@ fn make_load_immediate_data(dst: register::SixteenBit, data: &View) -> ParseOutp
|
|||
// indicates it should be.
|
||||
let value = u16::from_le_bytes([lower_bytes, upper_bytes]);
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::SixteenBitLoad(
|
||||
SixteenBitLoadInstruction::LoadImmediateToRegister { value, dst },
|
||||
),
|
||||
cycles: 12,
|
||||
},
|
||||
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::LoadImmediateToRegister {
|
||||
value,
|
||||
dst,
|
||||
}),
|
||||
3,
|
||||
)
|
||||
}
|
||||
|
@ -59,15 +57,10 @@ fn make_load_effective_address(dst: register::Combined, data: &View) -> ParseOut
|
|||
let signed_value = i8::from_be_bytes([unsigned_value]);
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::SixteenBitLoad(
|
||||
SixteenBitLoadInstruction::LoadEffectiveAddress {
|
||||
dst,
|
||||
offset: signed_value,
|
||||
},
|
||||
),
|
||||
cycles: 12,
|
||||
},
|
||||
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::LoadEffectiveAddress {
|
||||
dst,
|
||||
offset: signed_value,
|
||||
}),
|
||||
2,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
|
||||
use crate::cpu::instructions::{Instruction, RunnableInstruction};
|
||||
use crate::cpu::instructions::Instruction;
|
||||
use crate::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult};
|
||||
use crate::memory::{GetViewTuple, View};
|
||||
use crate::register;
|
||||
|
@ -59,14 +59,10 @@ impl OpcodeParser for Parser {
|
|||
|
||||
fn make_stack_operation_data(operation: Operation, reg: register::Combined) -> ParseOutput {
|
||||
let instruction = match operation {
|
||||
Operation::Push => RunnableInstruction {
|
||||
instruction: Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Push { src: reg }),
|
||||
cycles: 16,
|
||||
},
|
||||
Operation::Pop => RunnableInstruction {
|
||||
instruction: Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Pop { dst: reg }),
|
||||
cycles: 12,
|
||||
},
|
||||
Operation::Push => {
|
||||
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Push { src: reg })
|
||||
}
|
||||
Operation::Pop => Instruction::SixteenBitLoad(SixteenBitLoadInstruction::Pop { dst: reg }),
|
||||
};
|
||||
|
||||
(instruction, 1)
|
||||
|
@ -77,12 +73,9 @@ fn make_load_sp_to_address_data(data: &View) -> ParseOutput {
|
|||
let dst_address = u16::from_le_bytes([address_half1, address_half2]);
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::SixteenBitLoad(
|
||||
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address },
|
||||
),
|
||||
cycles: 20,
|
||||
},
|
||||
Instruction::SixteenBitLoad(
|
||||
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address },
|
||||
),
|
||||
3,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use crate::cpu::instructions::load16::SixteenBitLoadInstruction;
|
||||
use crate::cpu::instructions::Instruction;
|
||||
use crate::cpu::parse::ParseOutput;
|
||||
use crate::cpu::{
|
||||
instructions::RunnableInstruction,
|
||||
parse::{self, Error, OpcodeParser, ParseResult},
|
||||
};
|
||||
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
|
||||
use crate::memory::View;
|
||||
use crate::register;
|
||||
|
||||
|
@ -29,12 +26,7 @@ fn make_load_between_register_data(
|
|||
src: register::SixteenBit,
|
||||
) -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::SixteenBitLoad(
|
||||
SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src },
|
||||
),
|
||||
cycles: 8,
|
||||
},
|
||||
Instruction::SixteenBitLoad(SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src }),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use crate::cpu::instructions::load8::EightBitLoadInstruction;
|
||||
use crate::cpu::instructions::Instruction;
|
||||
use crate::cpu::parse::ParseOutput;
|
||||
use crate::cpu::{
|
||||
instructions::RunnableInstruction,
|
||||
parse::{self, Error, OpcodeParser, ParseResult},
|
||||
};
|
||||
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
|
||||
use crate::memory::{GetViewTuple, View};
|
||||
use crate::register;
|
||||
|
||||
|
@ -34,16 +31,10 @@ fn make_load_immediate_data(register: register::SingleEightBit, data: &View) ->
|
|||
let (_opcode, value) = data.get_tuple();
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadImmediateToRegister { register, value },
|
||||
),
|
||||
// TODO: I don't love that the cycles are in a parsing function,
|
||||
// but ultimately I want the cycles to be as close to the opcode as possible
|
||||
// so that it's easier to change. Maybe I can change this once I end up with
|
||||
// more of the instructions complete
|
||||
cycles: 8,
|
||||
},
|
||||
Instruction::EightBitLoad(EightBitLoadInstruction::LoadImmediateToRegister {
|
||||
register,
|
||||
value,
|
||||
}),
|
||||
2,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::cpu::instructions::load8::EightBitLoadInstruction;
|
||||
use crate::cpu::instructions::{Instruction, RunnableInstruction};
|
||||
use crate::cpu::instructions::Instruction;
|
||||
use crate::cpu::parse::{self, Error, OpcodeParser, ParseOutput, ParseResult};
|
||||
use crate::memory::{GetViewTuple, View};
|
||||
use crate::register;
|
||||
|
@ -186,12 +186,7 @@ fn make_load_from_register_address(
|
|||
src: register::Combined,
|
||||
) -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadFromRegisterAddress { src, dst },
|
||||
),
|
||||
cycles: 8,
|
||||
},
|
||||
Instruction::EightBitLoad(EightBitLoadInstruction::LoadFromRegisterAddress { src, dst }),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
@ -201,12 +196,7 @@ fn make_load_to_register_address(
|
|||
src: register::SingleEightBit,
|
||||
) -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadToRegisterAddress { src, dst },
|
||||
),
|
||||
cycles: 8,
|
||||
},
|
||||
Instruction::EightBitLoad(EightBitLoadInstruction::LoadToRegisterAddress { src, dst }),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
@ -217,12 +207,10 @@ fn make_load_from_immediate_address(dst: register::SingleEightBit, data: &View)
|
|||
// The manual states that the LSB of the address is specified first (i.e. little endian)
|
||||
let src_address = u16::from_le_bytes([lower_bytes, upper_bytes]);
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadFromImmediateAddress { src_address, dst },
|
||||
),
|
||||
cycles: 16,
|
||||
},
|
||||
Instruction::EightBitLoad(EightBitLoadInstruction::LoadFromImmediateAddress {
|
||||
src_address,
|
||||
dst,
|
||||
}),
|
||||
3,
|
||||
)
|
||||
}
|
||||
|
@ -233,12 +221,10 @@ fn make_load_to_immediate_address(src: register::SingleEightBit, data: &View) ->
|
|||
// The manual states that the LSB of the address is specified first (i.e. little endian)
|
||||
let dst_address = u16::from_le_bytes([lower_bytes, upper_bytes]);
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadToImmediateAddress { src, dst_address },
|
||||
),
|
||||
cycles: 16,
|
||||
},
|
||||
Instruction::EightBitLoad(EightBitLoadInstruction::LoadToImmediateAddress {
|
||||
src,
|
||||
dst_address,
|
||||
}),
|
||||
3,
|
||||
)
|
||||
}
|
||||
|
@ -246,12 +232,7 @@ fn make_load_to_immediate_address(src: register::SingleEightBit, data: &View) ->
|
|||
fn make_load_n_to_hl_address(data: &View) -> ParseOutput {
|
||||
let (_opcode, value) = data.get_tuple();
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(EightBitLoadInstruction::LoadnToHLAddress {
|
||||
value,
|
||||
}),
|
||||
cycles: 12,
|
||||
},
|
||||
Instruction::EightBitLoad(EightBitLoadInstruction::LoadnToHLAddress { value }),
|
||||
2,
|
||||
)
|
||||
}
|
||||
|
@ -261,16 +242,12 @@ fn make_load_from_memory_relative_to_io_register_start(
|
|||
dst: register::SingleEightBit,
|
||||
) -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStart {
|
||||
offset_register,
|
||||
dst,
|
||||
},
|
||||
),
|
||||
cycles: 8,
|
||||
},
|
||||
// guaranteed to succeed given we found the opcode
|
||||
Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStart {
|
||||
offset_register,
|
||||
dst,
|
||||
},
|
||||
),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
@ -280,15 +257,12 @@ fn make_load_to_memory_relative_to_io_register_start(
|
|||
src: register::SingleEightBit,
|
||||
) -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStart {
|
||||
src,
|
||||
offset_register,
|
||||
},
|
||||
),
|
||||
cycles: 8,
|
||||
},
|
||||
Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStart {
|
||||
src,
|
||||
offset_register,
|
||||
},
|
||||
),
|
||||
// guaranteed to succeed given we found the opcode
|
||||
1,
|
||||
)
|
||||
|
@ -301,16 +275,12 @@ fn make_load_to_memory_relative_to_io_register_start_by_immediate(
|
|||
let (_opcode, offset) = data.get_tuple();
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
|
||||
src,
|
||||
offset,
|
||||
},
|
||||
),
|
||||
// guaranteed to succeed given we got the value
|
||||
cycles: 12,
|
||||
},
|
||||
Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
|
||||
src,
|
||||
offset,
|
||||
},
|
||||
),
|
||||
2,
|
||||
)
|
||||
}
|
||||
|
@ -322,15 +292,12 @@ fn make_load_from_memory_relative_to_io_register_start_by_immediate(
|
|||
let (_opcode, offset) = data.get_tuple();
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStartByImmediate {
|
||||
offset,
|
||||
dst,
|
||||
},
|
||||
),
|
||||
cycles: 12,
|
||||
},
|
||||
Instruction::EightBitLoad(
|
||||
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStartByImmediate {
|
||||
offset,
|
||||
dst,
|
||||
},
|
||||
),
|
||||
2,
|
||||
)
|
||||
}
|
||||
|
@ -364,11 +331,5 @@ fn make_load_from_address_and_do_arithmetic<
|
|||
fn make_load_and_do_arithmetic<F: Fn() -> EightBitLoadInstruction>(make: F) -> ParseOutput {
|
||||
let load_instruction = make();
|
||||
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(load_instruction),
|
||||
cycles: 8,
|
||||
},
|
||||
1,
|
||||
)
|
||||
(Instruction::EightBitLoad(load_instruction), 1)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use crate::cpu::instructions::load8::EightBitLoadInstruction;
|
||||
use crate::cpu::instructions::Instruction;
|
||||
use crate::cpu::parse::ParseOutput;
|
||||
use crate::cpu::{
|
||||
instructions::RunnableInstruction,
|
||||
parse::{self, Error, OpcodeParser, ParseResult},
|
||||
};
|
||||
use crate::cpu::parse::{self, Error, OpcodeParser, ParseResult};
|
||||
use crate::memory::View;
|
||||
use crate::register;
|
||||
|
||||
|
@ -54,13 +51,7 @@ fn make_load_between_register_data(
|
|||
src: register::SingleEightBit,
|
||||
) -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::EightBitLoad(EightBitLoadInstruction::LoadBetweenRegisters {
|
||||
dst,
|
||||
src,
|
||||
}),
|
||||
cycles: 4,
|
||||
},
|
||||
Instruction::EightBitLoad(EightBitLoadInstruction::LoadBetweenRegisters { dst, src }),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{OpcodeParser, ParseOutput, ParseResult};
|
||||
use crate::{
|
||||
cpu::instructions::{misc::MiscInstruction, Instruction, RunnableInstruction},
|
||||
cpu::instructions::{misc::MiscInstruction, Instruction},
|
||||
memory::View,
|
||||
};
|
||||
|
||||
|
@ -20,41 +20,20 @@ impl OpcodeParser for Parser {
|
|||
}
|
||||
|
||||
fn build_set_carry_flag_data() -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::Misc(MiscInstruction::SetCarryFlag),
|
||||
cycles: 4,
|
||||
},
|
||||
1,
|
||||
)
|
||||
(Instruction::Misc(MiscInstruction::SetCarryFlag), 1)
|
||||
}
|
||||
|
||||
fn build_complement_carry_flag_data() -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::Misc(MiscInstruction::ComplementCarryFlag),
|
||||
cycles: 4,
|
||||
},
|
||||
1,
|
||||
)
|
||||
(Instruction::Misc(MiscInstruction::ComplementCarryFlag), 1)
|
||||
}
|
||||
|
||||
fn build_complement_a_register_data() -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::Misc(MiscInstruction::ComplementARegister),
|
||||
cycles: 4,
|
||||
},
|
||||
1,
|
||||
)
|
||||
(Instruction::Misc(MiscInstruction::ComplementARegister), 1)
|
||||
}
|
||||
|
||||
fn build_daa_data() -> ParseOutput {
|
||||
(
|
||||
RunnableInstruction {
|
||||
instruction: Instruction::Misc(MiscInstruction::DecimalAdjustAccumulator),
|
||||
cycles: 4,
|
||||
},
|
||||
Instruction::Misc(MiscInstruction::DecimalAdjustAccumulator),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -30,12 +30,18 @@ pub enum Error {
|
|||
|
||||
/// `Run` takes a single instruction and runs it on the given processor.
|
||||
trait Run {
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<(), Error>;
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error>;
|
||||
}
|
||||
|
||||
/// `Cycles` represents the number of cycles an operation took
|
||||
pub struct Cycles(pub u8);
|
||||
|
||||
/// `run_instruction` will run the given instruction on the processor.
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
pub fn run_instruction(processor: &mut Processor, instruction: Instruction) -> Result<(), Error> {
|
||||
pub fn run_instruction(
|
||||
processor: &mut Processor,
|
||||
instruction: Instruction,
|
||||
) -> Result<Cycles, Error> {
|
||||
match instruction {
|
||||
Instruction::EightBitLoad(load_instruction) => load_instruction.run_on(processor),
|
||||
Instruction::SixteenBitLoad(load_instruction) => load_instruction.run_on(processor),
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::{cpu::instructions::arith16::SixteenBitArithmeticInstruction, register};
|
||||
|
||||
use super::{arithutil::CarryingAdd, Run};
|
||||
use super::{arithutil::CarryingAdd, Cycles, Run};
|
||||
|
||||
impl Run for SixteenBitArithmeticInstruction {
|
||||
fn run_on(&self, processor: &mut crate::cpu::Processor) -> Result<(), super::Error> {
|
||||
fn run_on(&self, processor: &mut crate::cpu::Processor) -> Result<Cycles, super::Error> {
|
||||
match *self {
|
||||
SixteenBitArithmeticInstruction::IncrementRegister { operand_register } => {
|
||||
let register_value = processor.registers.get_16bit_register(operand_register);
|
||||
|
@ -12,7 +12,7 @@ impl Run for SixteenBitArithmeticInstruction {
|
|||
.registers
|
||||
.set_16bit_register(operand_register, incremented_value);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
SixteenBitArithmeticInstruction::DecrementRegister { operand_register } => {
|
||||
|
@ -22,7 +22,7 @@ impl Run for SixteenBitArithmeticInstruction {
|
|||
.registers
|
||||
.set_16bit_register(operand_register, decremented_value);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
SixteenBitArithmeticInstruction::AddRegisterToHL { operand_register } => {
|
||||
|
@ -45,7 +45,7 @@ impl Run for SixteenBitArithmeticInstruction {
|
|||
.registers
|
||||
.set_flag_bit(register::Flag::Subtract, 0);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
register,
|
||||
};
|
||||
|
||||
use super::{arithutil::CarryingAdd, Run};
|
||||
use super::{arithutil::CarryingAdd, Cycles, Run};
|
||||
|
||||
mod binary;
|
||||
mod unary;
|
||||
|
@ -26,7 +26,7 @@ struct OperationFlagOutput {
|
|||
}
|
||||
|
||||
impl Run for EightBitArithmeticInstruction {
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
|
||||
match self.operation {
|
||||
Operation::Add => binary::run_add(processor, self.operand),
|
||||
|
||||
|
@ -52,7 +52,7 @@ impl Run for EightBitArithmeticInstruction {
|
|||
}
|
||||
|
||||
impl Run for AdjustStackPointerInstruction {
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
|
||||
let stack_pointer = processor
|
||||
.registers
|
||||
.get_single_16bit_register(register::SingleSixteenBit::StackPointer);
|
||||
|
@ -72,7 +72,7 @@ impl Run for AdjustStackPointerInstruction {
|
|||
},
|
||||
);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(16))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
instructions::arith8::Operand,
|
||||
run::{
|
||||
arithutil::{self, CarriedNumber, CarryingAdd, CarryingSub},
|
||||
Error,
|
||||
Cycles, Error,
|
||||
},
|
||||
Processor,
|
||||
},
|
||||
|
@ -12,11 +12,11 @@ use crate::{
|
|||
|
||||
use super::{OperationFlagOutput, OperationOutput};
|
||||
|
||||
pub fn run_add(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_add(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
run_operation(processor, operand, run_add_on_operands)
|
||||
}
|
||||
|
||||
pub fn run_add_with_carry(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_add_with_carry(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
run_operation_with_carry(processor, operand, run_add_on_operands)
|
||||
}
|
||||
|
||||
|
@ -32,11 +32,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn run_sub(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_sub(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
run_operation(processor, operand, run_sub_on_operands)
|
||||
}
|
||||
|
||||
pub fn run_sub_with_carry(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_sub_with_carry(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
run_operation_with_carry(processor, operand, run_sub_on_operands)
|
||||
}
|
||||
|
||||
|
@ -51,20 +51,20 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn run_compare(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_compare(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
let a_value = processor.registers.a;
|
||||
// A compare is just a sub, preserving the A value, so we can just do a sub
|
||||
// and restore the original value
|
||||
run_sub(processor, operand)?;
|
||||
let sub_cycles = run_sub(processor, operand)?;
|
||||
|
||||
processor
|
||||
.registers
|
||||
.set_single_8bit_register(register::SingleEightBit::A, a_value);
|
||||
|
||||
Ok(())
|
||||
Ok(sub_cycles)
|
||||
}
|
||||
|
||||
pub fn run_and(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_and(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
run_operation(processor, operand, |lhs, rhs| {
|
||||
let total = lhs & rhs;
|
||||
|
||||
|
@ -80,7 +80,7 @@ pub fn run_and(processor: &mut Processor, operand: Operand) -> Result<(), Error>
|
|||
})
|
||||
}
|
||||
|
||||
pub fn run_or(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_or(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
run_operation(processor, operand, |lhs, rhs| {
|
||||
let total = lhs | rhs;
|
||||
|
||||
|
@ -96,7 +96,7 @@ pub fn run_or(processor: &mut Processor, operand: Operand) -> Result<(), Error>
|
|||
})
|
||||
}
|
||||
|
||||
pub fn run_xor(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_xor(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
run_operation(processor, operand, |lhs, rhs| {
|
||||
let total = lhs ^ rhs;
|
||||
|
||||
|
@ -112,28 +112,32 @@ pub fn run_xor(processor: &mut Processor, operand: Operand) -> Result<(), Error>
|
|||
})
|
||||
}
|
||||
|
||||
fn run_operation<F>(processor: &mut Processor, operand: Operand, operation: F) -> Result<(), Error>
|
||||
fn run_operation<F>(
|
||||
processor: &mut Processor,
|
||||
operand: Operand,
|
||||
operation: F,
|
||||
) -> Result<Cycles, Error>
|
||||
where
|
||||
F: FnOnce(u8, u8) -> OperationOutput,
|
||||
{
|
||||
let operand_values = gather_operand_values(processor, operand)?;
|
||||
run_operation_on_operands(processor, operand_values, operation);
|
||||
|
||||
Ok(())
|
||||
Ok(cycles_for_operand(operand))
|
||||
}
|
||||
|
||||
fn run_operation_with_carry<F>(
|
||||
processor: &mut Processor,
|
||||
operand: Operand,
|
||||
operation: F,
|
||||
) -> Result<(), Error>
|
||||
) -> Result<Cycles, Error>
|
||||
where
|
||||
F: FnOnce(u8, CarriedNumber<u8>) -> OperationOutput,
|
||||
{
|
||||
let operand_values = gather_operands_with_carry(processor, operand)?;
|
||||
run_operation_on_operands(processor, operand_values, operation);
|
||||
|
||||
Ok(())
|
||||
Ok(cycles_for_operand(operand))
|
||||
}
|
||||
|
||||
fn run_operation_on_operands<F, L, R>(processor: &mut Processor, (lhs, rhs): (L, R), operation: F)
|
||||
|
@ -235,6 +239,14 @@ fn addition_flags(total: u8, half_carry: bool, carry: bool) -> OperationFlagOutp
|
|||
}
|
||||
}
|
||||
|
||||
fn cycles_for_operand(operand: Operand) -> Cycles {
|
||||
match operand {
|
||||
Operand::SingleRegister(_register) => Cycles(4),
|
||||
Operand::HLAddressValue => Cycles(8),
|
||||
Operand::Immediate(_val) => Cycles(8),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
instructions::arith8::Operand,
|
||||
run::{
|
||||
arithutil::{CarryingAdd, CarryingSub},
|
||||
Error,
|
||||
Cycles, Error,
|
||||
},
|
||||
Processor,
|
||||
},
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
|||
|
||||
use super::{OperationFlagOutput, OperationOutput};
|
||||
|
||||
pub fn run_inc(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_inc(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
let current_carry_flag = processor.registers.get_flag_bit(register::Flag::Carry);
|
||||
run_operation(processor, operand, |value| {
|
||||
let (result, half_carry, _full_carry) = value.add_with_carry(1);
|
||||
|
@ -29,7 +29,7 @@ pub fn run_inc(processor: &mut Processor, operand: Operand) -> Result<(), Error>
|
|||
})
|
||||
}
|
||||
|
||||
pub fn run_dec(processor: &mut Processor, operand: Operand) -> Result<(), Error> {
|
||||
pub fn run_dec(processor: &mut Processor, operand: Operand) -> Result<Cycles, Error> {
|
||||
let current_carry_flag = processor.registers.get_flag_bit(register::Flag::Carry);
|
||||
run_operation(processor, operand, |value| {
|
||||
let (result, half_carry, _full_carry) = value.sub_with_carry(1);
|
||||
|
@ -46,7 +46,11 @@ pub fn run_dec(processor: &mut Processor, operand: Operand) -> Result<(), Error>
|
|||
})
|
||||
}
|
||||
|
||||
fn run_operation<F>(processor: &mut Processor, operand: Operand, operation: F) -> Result<(), Error>
|
||||
fn run_operation<F>(
|
||||
processor: &mut Processor,
|
||||
operand: Operand,
|
||||
operation: F,
|
||||
) -> Result<Cycles, Error>
|
||||
where
|
||||
F: Fn(u8) -> OperationOutput,
|
||||
{
|
||||
|
@ -56,7 +60,7 @@ where
|
|||
store_output_value(processor, operand, output.value)?;
|
||||
super::store_flags(processor, output.flags);
|
||||
|
||||
Ok(())
|
||||
Ok(cycles_for_operand(operand))
|
||||
}
|
||||
|
||||
fn gather_operand_value(processor: &mut Processor, operand: Operand) -> Result<u8, Error> {
|
||||
|
@ -122,3 +126,11 @@ fn store_output_value(
|
|||
Operand::Immediate(_) => unreachable!("cannot perform unary operation on an immediate"),
|
||||
}
|
||||
}
|
||||
|
||||
fn cycles_for_operand(operand: Operand) -> Cycles {
|
||||
match operand {
|
||||
Operand::SingleRegister(_register) => Cycles(4),
|
||||
Operand::HLAddressValue => Cycles(12),
|
||||
Operand::Immediate(_val) => unreachable!("Cannot perform unary on immediate"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
use super::arithutil::CarryingAdd;
|
||||
use super::{Error, Run};
|
||||
use super::{Cycles, Error, Run};
|
||||
use crate::cpu::{instructions::load16::SixteenBitLoadInstruction, Processor};
|
||||
use crate::{memory, register};
|
||||
|
||||
impl Run for SixteenBitLoadInstruction {
|
||||
// TODO: Fix this
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
|
||||
match *self {
|
||||
SixteenBitLoadInstruction::LoadImmediateToRegister { dst, value } => {
|
||||
processor.registers.set_16bit_register(dst, value);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(12))
|
||||
}
|
||||
|
||||
SixteenBitLoadInstruction::LoadBetweenRegisters { dst, src } => {
|
||||
let value = processor.registers.get_16bit_register(src);
|
||||
processor.registers.set_16bit_register(dst, value);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
SixteenBitLoadInstruction::LoadEffectiveAddress { dst, offset } => {
|
||||
|
@ -43,7 +43,7 @@ impl Run for SixteenBitLoadInstruction {
|
|||
|
||||
processor.registers.set_combined_register(dst, new_sp);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(12))
|
||||
}
|
||||
|
||||
SixteenBitLoadInstruction::Push { src } => {
|
||||
|
@ -74,7 +74,7 @@ impl Run for SixteenBitLoadInstruction {
|
|||
current_sp - 2,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(16))
|
||||
}
|
||||
|
||||
SixteenBitLoadInstruction::Pop { dst } => {
|
||||
|
@ -112,7 +112,7 @@ impl Run for SixteenBitLoadInstruction {
|
|||
current_sp + 2,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(12))
|
||||
}
|
||||
SixteenBitLoadInstruction::LoadStackPointerToImmediateAddress { dst_address } => {
|
||||
let current_sp = processor
|
||||
|
@ -126,7 +126,7 @@ impl Run for SixteenBitLoadInstruction {
|
|||
));
|
||||
|
||||
match memory_res {
|
||||
Ok(_) => Ok(()),
|
||||
Ok(_) => Ok(Cycles(20)),
|
||||
Err(memory::Error::GetInvalidAddress(bad_addr)) => {
|
||||
Err(Error::InvalidImmediateAddress(bad_addr))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::{Error, Run};
|
||||
use super::{Cycles, Error, Run};
|
||||
use crate::{
|
||||
cpu::{instructions::load8::EightBitLoadInstruction, Processor},
|
||||
memory, register,
|
||||
|
@ -7,35 +7,45 @@ use crate::{
|
|||
impl Run for EightBitLoadInstruction {
|
||||
// TODO: Break this up somehow
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
|
||||
match *self {
|
||||
EightBitLoadInstruction::LoadImmediateToRegister { value, register } => {
|
||||
processor
|
||||
.registers
|
||||
.set_single_8bit_register(register, value);
|
||||
Ok(())
|
||||
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadBetweenRegisters { dst, src } => {
|
||||
let src_value = processor.registers.get_single_8bit_register(src);
|
||||
processor.registers.set_single_8bit_register(dst, src_value);
|
||||
Ok(())
|
||||
|
||||
Ok(Cycles(4))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadFromRegisterAddress { src, dst } => {
|
||||
processor.load_from_register_address_to_register(dst, src)
|
||||
processor.load_from_register_address_to_register(dst, src)?;
|
||||
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadFromImmediateAddress { src_address, dst } => {
|
||||
processor.load_from_address_to_register(dst, src_address.into())
|
||||
processor.load_from_address_to_register(dst, src_address.into())?;
|
||||
|
||||
Ok(Cycles(16))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadToRegisterAddress { src, dst } => {
|
||||
processor.load_from_register_to_register_address(dst, src)
|
||||
processor.load_from_register_to_register_address(dst, src)?;
|
||||
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadToImmediateAddress { src, dst_address } => {
|
||||
processor.load_from_register_to_address(dst_address.into(), src)
|
||||
processor.load_from_register_to_address(dst_address.into(), src)?;
|
||||
|
||||
Ok(Cycles(16))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadnToHLAddress { value } => {
|
||||
|
@ -43,7 +53,9 @@ impl Run for EightBitLoadInstruction {
|
|||
.registers
|
||||
.get_combined_register(register::Combined::HL);
|
||||
|
||||
processor.load_8bit_immediate_to_address(dest_address.into(), value)
|
||||
processor.load_8bit_immediate_to_address(dest_address.into(), value)?;
|
||||
|
||||
Ok(Cycles(12))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStart {
|
||||
|
@ -56,7 +68,8 @@ impl Run for EightBitLoadInstruction {
|
|||
let src_address =
|
||||
memory::IO_REGISTER_START_ADDRESS + usize::from(src_address_offset);
|
||||
|
||||
processor.load_from_address_to_register(dst, src_address)
|
||||
processor.load_from_address_to_register(dst, src_address)?;
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStart {
|
||||
|
@ -69,7 +82,9 @@ impl Run for EightBitLoadInstruction {
|
|||
let dst_address =
|
||||
memory::IO_REGISTER_START_ADDRESS + usize::from(dst_address_offset);
|
||||
|
||||
processor.load_from_register_to_address(dst_address, src)
|
||||
processor.load_from_register_to_address(dst_address, src)?;
|
||||
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadFromRegisterAddressThenDec { dst, src } => {
|
||||
|
@ -80,7 +95,7 @@ impl Run for EightBitLoadInstruction {
|
|||
.registers
|
||||
.set_combined_register(src, src_address - 1);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadFromRegisterAddressThenInc { dst, src } => {
|
||||
|
@ -91,7 +106,7 @@ impl Run for EightBitLoadInstruction {
|
|||
.registers
|
||||
.set_combined_register(src, src_address + 1);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadToRegisterAddressThenDec { dst, src } => {
|
||||
|
@ -102,7 +117,7 @@ impl Run for EightBitLoadInstruction {
|
|||
.registers
|
||||
.set_combined_register(dst, dst_address - 1);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadToRegisterAddressThenInc { dst, src } => {
|
||||
|
@ -113,7 +128,7 @@ impl Run for EightBitLoadInstruction {
|
|||
.registers
|
||||
.set_combined_register(dst, dst_address + 1);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(8))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadToMemoryRelativeToIORegisterStartByImmediate {
|
||||
|
@ -121,7 +136,9 @@ impl Run for EightBitLoadInstruction {
|
|||
offset,
|
||||
} => {
|
||||
let dst_address = memory::IO_REGISTER_START_ADDRESS + usize::from(offset);
|
||||
processor.load_from_register_to_address(dst_address, src)
|
||||
processor.load_from_register_to_address(dst_address, src)?;
|
||||
|
||||
Ok(Cycles(12))
|
||||
}
|
||||
|
||||
EightBitLoadInstruction::LoadFromMemoryRelativeToIORegisterStartByImmediate {
|
||||
|
@ -129,7 +146,9 @@ impl Run for EightBitLoadInstruction {
|
|||
offset,
|
||||
} => {
|
||||
let src_address = memory::IO_REGISTER_START_ADDRESS + usize::from(offset);
|
||||
processor.load_from_address_to_register(dst, src_address)
|
||||
processor.load_from_address_to_register(dst, src_address)?;
|
||||
|
||||
Ok(Cycles(12))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,15 @@ use crate::{
|
|||
register::Registers,
|
||||
};
|
||||
|
||||
use super::Run;
|
||||
use super::{Cycles, Run};
|
||||
|
||||
impl Run for MiscInstruction {
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<(), Error> {
|
||||
fn run_on(&self, processor: &mut Processor) -> Result<Cycles, Error> {
|
||||
match *self {
|
||||
MiscInstruction::SetCarryFlag => {
|
||||
set_flags_in_carry_bit_instruction(processor, 1);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(4))
|
||||
}
|
||||
MiscInstruction::ComplementCarryFlag => {
|
||||
let current_carry_flag = processor.registers.get_flag_bit(register::Flag::Carry);
|
||||
|
@ -19,7 +19,7 @@ impl Run for MiscInstruction {
|
|||
|
||||
set_flags_in_carry_bit_instruction(processor, flipped);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(4))
|
||||
}
|
||||
MiscInstruction::ComplementARegister => {
|
||||
let current_value = processor
|
||||
|
@ -36,7 +36,7 @@ impl Run for MiscInstruction {
|
|||
.registers
|
||||
.set_flag_bit(register::Flag::Subtract, 1);
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(4))
|
||||
}
|
||||
MiscInstruction::DecimalAdjustAccumulator => {
|
||||
let (adjusted_a_value, carry) = get_daa_value(&processor.registers);
|
||||
|
@ -57,7 +57,7 @@ impl Run for MiscInstruction {
|
|||
.registers
|
||||
.set_flag_bit(register::Flag::Zero, (adjusted_a_value == 0).into());
|
||||
|
||||
Ok(())
|
||||
Ok(Cycles(4))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ferris_boi::{
|
||||
cpu::{instructions::RunnableInstruction, Processor},
|
||||
cpu::{instructions::Instruction, Processor},
|
||||
register,
|
||||
};
|
||||
|
||||
|
@ -21,11 +21,10 @@ fn test_add_hl_to_itself() {
|
|||
);
|
||||
let data = [0x29, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
0x4488,
|
||||
|
@ -60,11 +59,10 @@ fn test_add_hl_to_registers_value(
|
|||
.set_16bit_register(operand_register, operand_value);
|
||||
let data = [opcode, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
expected,
|
||||
|
@ -102,8 +100,7 @@ fn test_add_hl_to_registers_flags(
|
|||
.set_16bit_register(operand_register, operand_value);
|
||||
let data = [opcode, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
// Set all the register to the opposite we expect to ensure they all get set
|
||||
|
@ -112,7 +109,7 @@ fn test_add_hl_to_registers_flags(
|
|||
(0, 0, expected_flags.half_carry, expected_flags.carry),
|
||||
);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -150,11 +147,10 @@ fn test_increment(
|
|||
.expect("Failed to set flag bits");
|
||||
let data = [opcode, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
expected,
|
||||
|
@ -191,11 +187,10 @@ fn test_decrement(
|
|||
.expect("Failed to set flag bits");
|
||||
let data = [opcode, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
expected,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ferris_boi::{
|
||||
cpu::{instructions::RunnableInstruction, Processor},
|
||||
cpu::{instructions::Instruction, Processor},
|
||||
register,
|
||||
};
|
||||
|
||||
|
@ -25,11 +25,10 @@ fn test_add_a_to_itself() {
|
|||
processor.registers.a = 10;
|
||||
let data = [0x87, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(20, processor.registers.a);
|
||||
}
|
||||
|
@ -46,11 +45,10 @@ fn test_add_to_a_value(opcode: u8, src: register::SingleEightBit) {
|
|||
processor.registers.set_single_8bit_register(src, 20);
|
||||
let data = [opcode, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(30, processor.registers.a);
|
||||
}
|
||||
|
@ -93,11 +91,10 @@ fn test_add_register_to_a_flags(
|
|||
processor.registers.set_single_8bit_register(src, src_value);
|
||||
let data = [opcode, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -123,11 +120,10 @@ fn test_add_hl_addr_to_a_value() {
|
|||
|
||||
let data = [0x86, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0x46, processor.registers.a);
|
||||
}
|
||||
|
@ -166,11 +162,10 @@ fn test_add_hl_addr_to_a_flags(
|
|||
);
|
||||
|
||||
let data = [0x86, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -187,11 +182,10 @@ fn test_add_immediate_to_a_value() {
|
|||
processor.registers.a = 50;
|
||||
|
||||
let data = [0xC6, 0x13, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(69, processor.registers.a);
|
||||
}
|
||||
|
@ -217,11 +211,10 @@ fn test_add_immediate_to_a_flags(a_value: u8, n: u8, expected_flags: AdditionOpe
|
|||
);
|
||||
|
||||
let data = [0xC6, n, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -260,10 +253,9 @@ fn test_add_register_with_carry_to_a_value(
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
|
||||
let data = [opcode, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(expected_value, processor.registers.a);
|
||||
}
|
||||
|
@ -323,10 +315,9 @@ fn test_add_register_with_carry_to_a_flags(
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
|
||||
let data = [opcode, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -347,10 +338,9 @@ fn test_add_a_to_itself_with_carry_value(initial_value: u8, carry_bit: u8, expec
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
let data = [0x8F, 0x01];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(processor.registers.a, expected_value);
|
||||
}
|
||||
|
@ -381,10 +371,9 @@ fn test_add_a_to_itself_with_carry_flags(
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
let data = [0x8F, 0x01];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -410,10 +399,9 @@ fn test_add_immediate_with_carry_to_a_value(
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
let data = [0xCE, operand, 0x01];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(processor.registers.a, expected_value);
|
||||
}
|
||||
|
@ -446,10 +434,9 @@ fn test_add_immediate_with_carry_to_a_flags(
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
let data = [0xCE, operand, 0x01];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -479,11 +466,10 @@ fn test_add_hl_addr_to_a_with_carry_value(carry_flag: u8, expected: u8) {
|
|||
|
||||
let data = [0x8E, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(expected, processor.registers.a);
|
||||
}
|
||||
|
@ -526,11 +512,10 @@ fn test_add_hl_addr_to_a_with_carry_flags(
|
|||
|
||||
let data = [0x8E, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -567,11 +552,10 @@ fn test_sub_register_from_a_value(
|
|||
|
||||
let data = [opcode, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(processor.registers.a, expected);
|
||||
}
|
||||
|
||||
|
@ -613,11 +597,10 @@ fn test_sub_register_from_a_flags(
|
|||
);
|
||||
|
||||
let data = [opcode, 0x02];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -634,14 +617,13 @@ fn test_sub_a_from_itself() {
|
|||
processor.registers.a = 0xFF;
|
||||
|
||||
let data = [0x97, 0x02];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
// Set all the register to the opposite we expect to ensure they all get set
|
||||
testutil::set_opposite_of_expected_flags(&mut processor, (0, 0, 1, 1));
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -681,11 +663,10 @@ fn test_sub_register_with_carry_from_a_value(
|
|||
|
||||
let data = [opcode, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(processor.registers.a, expected);
|
||||
}
|
||||
#[test_matrix(
|
||||
|
@ -739,10 +720,9 @@ fn test_sub_register_from_carry_from_a_flags(
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
|
||||
let data = [opcode, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -759,11 +739,10 @@ fn test_subtract_immediate_from_a_value() {
|
|||
processor.registers.a = 0xFF;
|
||||
let data = [0xD6, 0x0F, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(processor.registers.a, 0xF0);
|
||||
}
|
||||
|
||||
|
@ -791,10 +770,9 @@ fn test_sub_immediate_from_a_flags(
|
|||
);
|
||||
|
||||
let data = [0xD6, operand, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -821,11 +799,10 @@ fn test_sub_immediate_with_carry_from_a_value(
|
|||
|
||||
let data = [0xDE, operand, 0x02];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x02]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(processor.registers.a, expected);
|
||||
}
|
||||
|
||||
|
@ -864,10 +841,9 @@ fn test_sub_immediate_from_carry_from_a_flags(
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
|
||||
let data = [0xDE, operand, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -888,10 +864,9 @@ fn test_sub_a_register_from_itself_with_carry_value(carry_bit: u8, expected: u8)
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
|
||||
let data = [0x9F, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(expected, processor.registers.a);
|
||||
}
|
||||
|
@ -920,10 +895,9 @@ fn test_sub_a_register_from_itself_with_carry_flags(
|
|||
.set_flag_bit(register::Flag::Carry, carry_bit);
|
||||
|
||||
let data = [0x9F, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -948,10 +922,9 @@ fn test_sub_hl_addr_from_a_value() {
|
|||
.set_combined_register(register::Combined::HL, 0xABCD);
|
||||
|
||||
let data = [0x96, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0x11, processor.registers.a);
|
||||
}
|
||||
|
@ -988,10 +961,9 @@ fn test_sub_hl_addr_from_a_flags(
|
|||
.set_combined_register(register::Combined::HL, 0xABCD);
|
||||
|
||||
let data = [0x96, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1020,10 +992,9 @@ fn test_sub_hl_from_a_flags(a_value: u8, operand_value: u8, carry_bit: u8, expec
|
|||
.set_combined_register(register::Combined::HL, 0xABCD);
|
||||
|
||||
let data = [0x9E, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(expected_value, processor.registers.a);
|
||||
}
|
||||
|
@ -1069,10 +1040,9 @@ fn test_sub_hl_addr_from_a_with_carry_flags(
|
|||
.set_combined_register(register::Combined::HL, 0xABCD);
|
||||
|
||||
let data = [0x9E, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1103,10 +1073,9 @@ fn test_and_single_register_with_a_value(
|
|||
.set_single_8bit_register(operand_register, operand);
|
||||
|
||||
let data = [opcode, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(expected_value, processor.registers.a);
|
||||
}
|
||||
|
@ -1137,10 +1106,9 @@ fn test_and_single_register_with_a_flags(
|
|||
.set_single_8bit_register(operand_register, operand);
|
||||
|
||||
let data = [opcode, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1157,10 +1125,9 @@ fn test_and_a_with_itself_value() {
|
|||
processor.registers.a = 0xAB;
|
||||
|
||||
let data = [0xA7, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0xAB, processor.registers.a);
|
||||
}
|
||||
|
@ -1174,10 +1141,9 @@ fn test_and_a_with_itself_flags() {
|
|||
processor.registers.a = 0xAB;
|
||||
|
||||
let data = [0xA7, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1201,10 +1167,9 @@ fn test_and_hl_value_with_a_value() {
|
|||
.expect("failed to set value");
|
||||
|
||||
let data = [0xA6, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0xA0, processor.registers.a);
|
||||
}
|
||||
|
@ -1226,10 +1191,9 @@ fn test_and_hl_value_with_a_flags(a_value: u8, operand: u8, expected_zero_flag:
|
|||
testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 1, 0));
|
||||
|
||||
let data = [0xA6, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1246,10 +1210,9 @@ fn test_and_immediate_with_a_value() {
|
|||
processor.registers.a = 0xAB;
|
||||
|
||||
let data = [0xE6, 0x0F, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0x0B, processor.registers.a);
|
||||
}
|
||||
|
@ -1264,10 +1227,9 @@ fn test_and_immediate_with_a_flags(a_value: u8, operand: u8, expected_zero_flag:
|
|||
testutil::set_opposite_of_expected_flags(&mut processor, (expected_zero_flag, 0, 1, 0));
|
||||
|
||||
let data = [0xE6, operand, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1300,10 +1262,9 @@ fn test_xor_register_with_a_value(
|
|||
.set_single_8bit_register(operand_register, operand);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(expected_value, processor.registers.a);
|
||||
}
|
||||
|
@ -1336,10 +1297,9 @@ fn test_xor_register_with_a_flags(
|
|||
.set_single_8bit_register(operand_register, operand);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1356,10 +1316,9 @@ fn test_xor_register_a_with_itself_value() {
|
|||
processor.registers.a = 0x45;
|
||||
|
||||
let data = [0xAF, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0, processor.registers.a);
|
||||
}
|
||||
|
@ -1372,10 +1331,9 @@ fn test_xor_register_a_with_itself_flags() {
|
|||
processor.registers.a = 0x45;
|
||||
|
||||
let data = [0xAF, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1402,10 +1360,9 @@ fn test_xor_hl_value_with_a_value() {
|
|||
.expect("failed to set memory value");
|
||||
|
||||
let data = [0xAE, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0x55, processor.registers.a);
|
||||
}
|
||||
|
@ -1428,10 +1385,9 @@ fn test_xor_hl_value_with_a_flags(a_value: u8, operand: u8, expected_zero_flag:
|
|||
.expect("failed to set memory value");
|
||||
|
||||
let data = [0xAE, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1450,10 +1406,9 @@ fn test_xor_immediate_value_with_a_value() {
|
|||
.set_single_8bit_register(register::SingleEightBit::A, 0x22);
|
||||
|
||||
let data = [0xEE, 0xEE, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0xCC, processor.registers.a);
|
||||
}
|
||||
|
@ -1468,10 +1423,9 @@ fn test_xor_immediate_value_with_a_flags(a_value: u8, operand: u8, expected_zero
|
|||
.set_single_8bit_register(register::SingleEightBit::A, a_value);
|
||||
|
||||
let data = [0xEE, operand, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1509,10 +1463,9 @@ fn test_or_register_with_a_value(
|
|||
.set_single_8bit_register(operand_register, operand);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(expected_value, processor.registers.a);
|
||||
}
|
||||
|
@ -1545,10 +1498,9 @@ fn test_or_register_with_a_flags(
|
|||
.set_single_8bit_register(operand_register, operand);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1565,10 +1517,9 @@ fn test_or_register_a_with_itself_value() {
|
|||
processor.registers.a = 0x45;
|
||||
|
||||
let data = [0xB7, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0x45, processor.registers.a);
|
||||
}
|
||||
|
@ -1582,10 +1533,9 @@ fn test_or_register_a_with_itself_flags(operand: u8, expected_zero_flag: u8) {
|
|||
processor.registers.a = operand;
|
||||
|
||||
let data = [0xB7, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1612,10 +1562,9 @@ fn test_or_hl_value_with_a_value() {
|
|||
.expect("failed to set memory value");
|
||||
|
||||
let data = [0xB6, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0xBB, processor.registers.a);
|
||||
}
|
||||
|
@ -1639,10 +1588,9 @@ fn test_or_hl_value_with_a_flags(a_value: u8, hl_value: u8, expected_zero_flag:
|
|||
.expect("failed to set memory value");
|
||||
|
||||
let data = [0xB7, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1661,10 +1609,9 @@ fn test_or_immediate_value_with_a_value() {
|
|||
.set_single_8bit_register(register::SingleEightBit::A, 0x33);
|
||||
|
||||
let data = [0xF6, 0xAA, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0xBB, processor.registers.a);
|
||||
}
|
||||
|
@ -1679,10 +1626,9 @@ fn test_or_immediate_value_with_a_flags(a_value: u8, operand: u8, expected_zero_
|
|||
.set_single_8bit_register(register::SingleEightBit::A, a_value);
|
||||
|
||||
let data = [0xF6, operand, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1710,10 +1656,9 @@ fn test_compare_register_instructions_do_not_modify_register_values(
|
|||
processor.registers.set_single_8bit_register(register, 0x22);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
0xFF,
|
||||
|
@ -1733,10 +1678,9 @@ fn test_compare_register_with_itself_does_not_modify_value() {
|
|||
.set_single_8bit_register(register::SingleEightBit::A, 0xFF);
|
||||
|
||||
let data = [0xBF, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
0xFF,
|
||||
|
@ -1767,10 +1711,9 @@ fn test_comparing_equal_values_between_registers_sets_zero_flag(
|
|||
processor.registers.set_single_8bit_register(register, 0xFF);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
0xFF,
|
||||
|
@ -1808,10 +1751,9 @@ fn test_comparing_extremely_less_than_values_between_registers_should_set_no_fla
|
|||
processor.registers.set_single_8bit_register(register, 0x01);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1842,10 +1784,9 @@ fn test_comparing_extremely_somewhat_less_than_values_between_registers_should_s
|
|||
processor.registers.set_single_8bit_register(register, 0x1F);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1876,10 +1817,9 @@ fn test_comparing_greater_than_values_between_registers_should_set_carry_flag(
|
|||
processor.registers.set_single_8bit_register(register, 0xFF);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1910,10 +1850,9 @@ fn test_comparing_lower_nibble_greater_than_values_between_registers_should_set_
|
|||
processor.registers.set_single_8bit_register(register, 0x2F);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -1940,10 +1879,9 @@ fn test_comparing_hl_value_to_a_does_not_change_value() {
|
|||
.expect("failde to set value");
|
||||
|
||||
let data = [0xBE, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
0xFF,
|
||||
|
@ -1984,10 +1922,9 @@ fn test_comparing_hl_value_to_a(a_value: u8, operand: u8, expected_flags: Additi
|
|||
);
|
||||
|
||||
let data = [0xBE, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -2006,10 +1943,9 @@ fn test_comparing_immediate_value_to_a_does_not_change_value() {
|
|||
.set_single_8bit_register(register::SingleEightBit::A, 0xFF);
|
||||
|
||||
let data = [0xFE, 0xBB, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
0xFF,
|
||||
|
@ -2046,10 +1982,9 @@ fn test_comparing_immediate_value_to_a(
|
|||
);
|
||||
|
||||
let data = [0xFE, operand, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -2102,10 +2037,9 @@ fn test_increment_decrement_single_register_value(
|
|||
.set_single_8bit_register(register, initial_value);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
expected_value,
|
||||
|
@ -2168,10 +2102,9 @@ fn test_increment_decrement_single_register_flags(
|
|||
);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -2198,10 +2131,9 @@ fn test_increment_decrement_hl_value(opcode: u8, initial_value: u8, expected_val
|
|||
.expect("failed to set memory value");
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
expected_value,
|
||||
|
@ -2246,10 +2178,9 @@ fn test_increment_decrement_hl_flags(
|
|||
);
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -2273,10 +2204,9 @@ fn test_adjust_stack_pointer_value(initial_sp: u16, adjustment: i8, expected_sp:
|
|||
|
||||
let twos_comp_adjustment = adjustment.to_be_bytes()[0];
|
||||
let data = [0xE8, twos_comp_adjustment, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(expected_sp, processor.registers.stack_pointer);
|
||||
}
|
||||
|
@ -2298,10 +2228,9 @@ fn test_adjust_stack_pointer(initial_sp: u16, adjustment: i8, half_carry: bool,
|
|||
|
||||
let twos_comp_adjustment = adjustment.to_be_bytes()[0];
|
||||
let data = [0xE8, twos_comp_adjustment, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ferris_boi::{
|
||||
cpu::{instructions::RunnableInstruction, Processor},
|
||||
cpu::{instructions::Instruction, Processor},
|
||||
register,
|
||||
};
|
||||
|
||||
|
@ -21,11 +21,10 @@ fn test_load_to_register_address_then_do_arithmetic(
|
|||
processor.registers.a = 10;
|
||||
|
||||
let data = [opcode, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(10, processor.memory.get(hl_value_before.into()).unwrap());
|
||||
assert_eq!(
|
||||
hl_value_after,
|
||||
|
@ -51,11 +50,10 @@ fn test_load_16bit_immediate_to_register(opcode: u8, expected_dst_register: regi
|
|||
// l05c0: ld hl,0ff02h ; 05c0 21 02 ff !..
|
||||
let data = [opcode, 0x34, 0x12, 0x05];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x05]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
0x1234,
|
||||
|
@ -73,11 +71,10 @@ fn test_load_from_hl_to_sp() {
|
|||
.set_combined_register(register::Combined::HL, 0x1234);
|
||||
let data = [0xF9, 0x00];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0x1234, processor.registers.stack_pointer);
|
||||
}
|
||||
|
@ -106,11 +103,10 @@ fn test_load_effective_address(start_sp: u16, value: i8, expected_sp: u16) {
|
|||
|
||||
let data = [0xF8, unsigned_value, 0x00];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
expected_sp,
|
||||
|
@ -142,11 +138,10 @@ fn test_load_effective_address_flags(starting_sp: u16, add_value: i8, half_carry
|
|||
};
|
||||
|
||||
let data = [0xF8, unsigned_value, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -166,11 +161,10 @@ fn test_stack_push(opcode: u8, src: register::Combined) {
|
|||
processor.registers.stack_pointer = 0xFFFE;
|
||||
let data = [opcode, 0x01];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
// we want to pop the LSB first (i.e. we write the MSB first)
|
||||
// https://rgbds.gbdev.io/docs/v0.5.2/gbz80.7#PUSH_r16
|
||||
|
@ -188,11 +182,10 @@ fn test_stack_push_from_af() {
|
|||
processor.registers.stack_pointer = 0xFFFE;
|
||||
let data = [0xF5, 0x01];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
// we want to pop the LSB first (i.e. we write the MSB first)
|
||||
// https://rgbds.gbdev.io/docs/v0.5.2/gbz80.7#PUSH_r16
|
||||
|
@ -213,11 +206,10 @@ fn test_stack_pop(opcode: u8, dst: register::Combined) {
|
|||
.expect("failed to set values in memory");
|
||||
let data = [opcode, 0x01];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0x1234, processor.registers.get_combined_register(dst));
|
||||
assert_eq!(0xFFF0 + 2, processor.registers.stack_pointer);
|
||||
|
@ -233,11 +225,10 @@ fn test_stack_pop_to_af() {
|
|||
.expect("failed to set values in memory");
|
||||
let data = [0xF1, 0x01];
|
||||
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x01]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(
|
||||
0x1230,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ferris_boi::{
|
||||
cpu::{instructions::RunnableInstruction, Processor},
|
||||
cpu::{instructions::Instruction, Processor},
|
||||
register,
|
||||
};
|
||||
use test_case::test_case;
|
||||
|
@ -65,13 +65,12 @@ fn test_load_register(
|
|||
.set_single_8bit_register(src_register, 0x45);
|
||||
|
||||
let data = [load_opcode, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
// assert our extra data after the instruction is returned
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(
|
||||
0x45,
|
||||
processor.registers.get_single_8bit_register(dst_register)
|
||||
|
@ -88,14 +87,13 @@ fn test_load_register(
|
|||
fn test_load_immediate(load_opcode: u8, expected_register: register::SingleEightBit) {
|
||||
let mut processor = Processor::default();
|
||||
let data = [load_opcode, 0x23, 0x00, 0x01];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
// assert our extra data after the instruction is returned
|
||||
// this data is just garbage; no idea if it's a valid instruction
|
||||
assert_eq!(extra_data, &[0x00, 0x01]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(
|
||||
0x23,
|
||||
processor
|
||||
|
@ -127,12 +125,11 @@ fn test_load_from_memory(
|
|||
.set_combined_register(expected_deref_register, 0xCCDD);
|
||||
|
||||
let data = [opcode, 0x10, 0x20];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse isntruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse isntruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x10, 0x20]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(
|
||||
105,
|
||||
processor
|
||||
|
@ -168,12 +165,11 @@ fn test_load_to_memory(
|
|||
.set_combined_register(expected_deref_register, 0xCCCC);
|
||||
|
||||
let data = [opcode, 0x10, 0x20];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x10, 0x20]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(0xCC, processor.memory.get(0xCCCC).unwrap());
|
||||
}
|
||||
|
||||
|
@ -185,11 +181,10 @@ fn test_load_immediate_to_memory() {
|
|||
.set_combined_register(register::Combined::HL, 0xCCDE);
|
||||
|
||||
let data = [0x36, 0x1D, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(0x1D, processor.memory.get(0xCCDE).unwrap());
|
||||
}
|
||||
|
||||
|
@ -202,11 +197,10 @@ fn test_load_from_immediate_address() {
|
|||
.expect("failed to set memory value");
|
||||
|
||||
let data = [0xFA, 0xDE, 0xCC, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(105, processor.registers.a);
|
||||
}
|
||||
|
||||
|
@ -215,11 +209,10 @@ fn test_load_to_immadiate_address() {
|
|||
let mut processor = Processor::default();
|
||||
processor.registers.a = 105;
|
||||
let data = [0xEA, 0xDE, 0xCC, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(105, processor.memory.get(0xCCDE).unwrap());
|
||||
}
|
||||
|
||||
|
@ -233,11 +226,10 @@ fn test_load_from_io_register_zone() {
|
|||
processor.registers.c = 0x64;
|
||||
|
||||
let data = [0xF2, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(10, processor.registers.a);
|
||||
}
|
||||
|
||||
|
@ -248,11 +240,10 @@ fn test_load_to_io_register_zone() {
|
|||
processor.registers.a = 10;
|
||||
|
||||
let data = [0xE2, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(10, processor.memory.get(0xFF64).unwrap());
|
||||
}
|
||||
|
||||
|
@ -273,11 +264,10 @@ fn test_load_from_register_address_then_do_arithmetic(
|
|||
.expect("failed to set memory value");
|
||||
|
||||
let data = [opcode, 0x00];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x00]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
assert_eq!(10, processor.registers.a);
|
||||
assert_eq!(
|
||||
hl_value_after,
|
||||
|
@ -293,11 +283,10 @@ fn test_load_to_io_register_zone_by_immediate() {
|
|||
processor.registers.a = 0xAF;
|
||||
|
||||
let data = [0xE0, 0x05, 0x06];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x06]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0xAF, processor.memory.get(0xFF05).unwrap());
|
||||
}
|
||||
|
@ -311,11 +300,10 @@ fn test_load_from_io_register_zone_by_immediate() {
|
|||
.expect("failed to set memory value");
|
||||
|
||||
let data = [0xF0, 0x05, 0x06];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x06]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0xAF, processor.registers.a);
|
||||
}
|
||||
|
@ -326,12 +314,11 @@ fn test_load_from_bottom_of_so_to_immediate_address() {
|
|||
processor.registers.stack_pointer = 0xABCD;
|
||||
|
||||
let data = [0x08, 0xAA, 0xFF, 0x06];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x06]);
|
||||
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
let bottom_stored_value = processor.memory.get_from(0xFFAA).unwrap().get();
|
||||
let top_stored_value = processor.memory.get_from(0xFFAB).unwrap().get();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::testutil::{self, assert_flags_eq};
|
||||
use ferris_boi::{
|
||||
cpu::{instructions::RunnableInstruction, Processor},
|
||||
cpu::{instructions::Instruction, Processor},
|
||||
register,
|
||||
};
|
||||
use test_case::test_case;
|
||||
|
@ -25,11 +25,10 @@ fn test_set_carry_flag_always_sets_to_1(starting_value: u8) {
|
|||
.set_flag_bit(register::Flag::Carry, starting_value);
|
||||
|
||||
let data = [0x37, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
let new_carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
|
||||
assert_eq!(1, new_carry_bit);
|
||||
|
@ -44,11 +43,10 @@ fn test_complement_carry_bit(starting_value: u8, expected_value: u8) {
|
|||
.set_flag_bit(register::Flag::Carry, starting_value);
|
||||
|
||||
let data = [0x3F, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
let new_carry_bit = processor.registers.get_flag_bit(register::Flag::Carry);
|
||||
assert_eq!(expected_value, new_carry_bit);
|
||||
|
@ -61,11 +59,10 @@ fn test_all_carry_bit_instructions_adjust_flags(opcode: u8) {
|
|||
testutil::set_opposite_of_expected_flags(&mut processor, (0, 0, 0, 1));
|
||||
|
||||
let data = [opcode, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -84,11 +81,10 @@ fn test_complement_a_register_value() {
|
|||
processor.registers.a = 0xF0;
|
||||
|
||||
let data = [0x2F, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(0x0F, processor.registers.a);
|
||||
}
|
||||
|
@ -100,11 +96,10 @@ fn test_complement_a_register_flags() {
|
|||
testutil::set_opposite_of_expected_flags(&mut processor, (0, 1, 1, 0));
|
||||
|
||||
let data = [0x2F, 0x03];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x03]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
testutil::assert_flags_eq!(
|
||||
processor,
|
||||
|
@ -150,11 +145,10 @@ fn test_daa(
|
|||
.set_flag_bit(register::Flag::Zero, (!expected_flags.zero).into());
|
||||
|
||||
let data = [0x27, 0x06];
|
||||
let (ins, extra_data) =
|
||||
RunnableInstruction::from_data(&data).expect("could not parse instruction");
|
||||
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
||||
|
||||
assert_eq!(extra_data, &[0x06]);
|
||||
processor.run_instruction(&ins);
|
||||
processor.run_instruction(ins);
|
||||
|
||||
assert_eq!(expected_a_value, processor.registers.a);
|
||||
assert_flags_eq!(
|
||||
|
|
Loading…
Reference in New Issue