115 lines
3.8 KiB
Rust
115 lines
3.8 KiB
Rust
use ferris_boi::{
|
|
cpu::{instructions::Instruction, Processor},
|
|
register::Flag,
|
|
};
|
|
use test_case::test_case;
|
|
|
|
#[test]
|
|
fn test_can_jump_to_immediate() {
|
|
let mut processor = Processor::default();
|
|
|
|
let data = [0xC3, 0x37, 0x13, 0x06];
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
|
|
assert_eq!(extra_data, &[0x06]);
|
|
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(0x1337, processor.registers.program_counter);
|
|
}
|
|
|
|
#[test]
|
|
fn test_call_adjusts_program_counter_to_given_value() {
|
|
let mut processor = Processor::default();
|
|
|
|
let data = [0xCD, 0x37, 0x13, 0x06];
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
|
|
assert_eq!(extra_data, &[0x06]);
|
|
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(0x1337, processor.registers.program_counter);
|
|
}
|
|
|
|
#[test]
|
|
fn test_call_pushes_pc_onto_stack() {
|
|
let mut processor = Processor::default();
|
|
processor.registers.program_counter = 0xBEEF;
|
|
|
|
let data = [0xCD, 0x37, 0x13, 0x06];
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
|
|
assert_eq!(extra_data, &[0x06]);
|
|
|
|
let old_sp = processor.registers.stack_pointer;
|
|
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(0xBE, processor.memory.get((old_sp - 1).into()).unwrap());
|
|
// 0xEF + 3, which is the size of the CALL instruction
|
|
assert_eq!(0xF2, processor.memory.get((old_sp - 2).into()).unwrap());
|
|
assert_eq!(old_sp - 2, processor.registers.stack_pointer);
|
|
}
|
|
|
|
#[test_case(0xCC, Flag::Zero, 1; "CALL Z")]
|
|
#[test_case(0xDC, Flag::Carry, 1; "CALL C")]
|
|
#[test_case(0xC4, Flag::Zero, 0; "CALL NZ")]
|
|
#[test_case(0xD4, Flag::Carry, 0; "CALL NC")]
|
|
fn test_call_jumps_if_condition_matches(opcode: u8, flag: Flag, expected_value: u8) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.set_flag_bit(flag, expected_value);
|
|
|
|
let data = [opcode, 0x37, 0x13, 0x06];
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
|
|
assert_eq!(extra_data, &[0x06]);
|
|
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(0x1337, processor.registers.program_counter);
|
|
}
|
|
|
|
#[test_case(0xCC, Flag::Zero, 1; "CALL Z")]
|
|
#[test_case(0xDC, Flag::Carry, 1; "CALL C")]
|
|
#[test_case(0xC4, Flag::Zero, 0; "CALL NZ")]
|
|
#[test_case(0xD4, Flag::Carry, 0; "CALL NC")]
|
|
fn test_call_grows_stack_if_condition_matches(opcode: u8, flag: Flag, expected_value: u8) {
|
|
let mut processor = Processor::default();
|
|
processor.registers.set_flag_bit(flag, expected_value);
|
|
|
|
let data = [opcode, 0x37, 0x13, 0x06];
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
|
|
assert_eq!(extra_data, &[0x06]);
|
|
|
|
let old_sp = processor.registers.stack_pointer;
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(old_sp - 2, processor.registers.stack_pointer);
|
|
}
|
|
|
|
#[test_case(0xCC, Flag::Zero, 1; "CALL Z")]
|
|
#[test_case(0xDC, Flag::Carry, 1; "CALL C")]
|
|
#[test_case(0xC4, Flag::Zero, 0; "CALL NZ")]
|
|
#[test_case(0xD4, Flag::Carry, 0; "CALL NC")]
|
|
fn test_call_does_nothing_if_condition_fails(opcode: u8, flag: Flag, expected_value: u8) {
|
|
let mut processor = Processor::default();
|
|
processor
|
|
.registers
|
|
.set_flag_bit(flag, if expected_value == 0 { 1 } else { 0 });
|
|
|
|
let data = [opcode, 0x37, 0x13, 0x06];
|
|
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
|
|
|
|
assert_eq!(extra_data, &[0x06]);
|
|
|
|
let old_sp = processor.registers.stack_pointer;
|
|
let old_pc = processor.registers.program_counter;
|
|
processor.run_instruction(ins);
|
|
|
|
assert_eq!(old_sp, processor.registers.stack_pointer);
|
|
// run_instruction does not advance the program counter, so this will be the same. Normally it would be old_pc plus 3
|
|
assert_eq!(old_pc, processor.registers.program_counter);
|
|
}
|