Compare commits

...

1 Commits

50 changed files with 134 additions and 48 deletions

View File

@ -9,4 +9,8 @@ pub enum BitManipulationInstruction {
SetHLValueBit {
bit: u8,
},
ResetRegisterBit {
register: register::SingleEightBit,
bit: u8,
},
}

View File

@ -1,4 +1,4 @@
use super::{unparsed::Opcode, OpcodeParser, ParseResult};
use super::{unparsed::Opcode, OpcodeParser, OrParse, ParseResult};
use crate::{
cpu::{
instructions::{manip::BitManipulationInstruction, Instruction},
@ -19,7 +19,7 @@ impl OpcodeParser for Parser {
fn parse_opcode(data: &View) -> ParseResult {
let opcode = parse::get_opcode_from_data(data);
parse_set_opcode(opcode)
parse_set_opcode(opcode).or_parse(parse_res_opcode)
}
}
@ -44,6 +44,27 @@ fn parse_set_opcode(opcode: Opcode) -> ParseResult {
Ok((Instruction::BitManipulation(ins), 2))
}
fn parse_res_opcode(opcode: Opcode) -> ParseResult {
let Opcode::SixteenBit(sixteen_bit_opcode) = opcode else {
return Err(parse::Error::UnknownOpcode(opcode));
};
if !(0xCB_80..=0xCB_BF).contains(&sixteen_bit_opcode) {
return Err(parse::Error::UnknownOpcode(opcode));
}
let bit = bit_for_reset_opcode(sixteen_bit_opcode)?;
let operand = operand_for_opcode(sixteen_bit_opcode)?;
let ins = match operand {
OpcodeOperand::HLValue => todo!(),
OpcodeOperand::Register(register) => {
BitManipulationInstruction::ResetRegisterBit { register, bit }
}
};
Ok((Instruction::BitManipulation(ins), 2))
}
fn operand_for_opcode(opcode: u16) -> Result<OpcodeOperand, parse::Error> {
let register_nibble = opcode & 0x000F;
match register_nibble {
@ -69,3 +90,14 @@ fn bit_for_set_opcode(opcode: u16) -> Result<u8, parse::Error> {
// Given the range we've constrained to, this has to be able to fit in 8 bits
Ok(bit.try_into().unwrap())
}
fn bit_for_reset_opcode(opcode: u16) -> Result<u8, parse::Error> {
if !(0xCB_80..=0xCB_BF).contains(&opcode) {
return Err(parse::Error::UnknownOpcode(opcode.into()));
}
let bit = (opcode - 0xCB_80) / 8;
// Given the range we've constrained to, this has to be able to fit in 8 bits
Ok(bit.try_into().unwrap())
}

View File

@ -58,6 +58,17 @@ impl Run for BitManipulationInstruction {
Ok(Cycles(16))
}
BitManipulationInstruction::ResetRegisterBit { register, bit } => {
let register_value = processor.registers.get_single_8bit_register(register);
let upd_value = clear_nth_bit(register_value, bit);
processor
.registers
.set_single_8bit_register(register, upd_value);
Ok(Cycles(8))
}
}
}
}
@ -67,3 +78,9 @@ fn set_nth_bit(value: u8, bit: u8) -> u8 {
value | (0x1 << bit)
}
fn clear_nth_bit(value: u8, bit: u8) -> u8 {
assert!(bit < 8, "Cannot set a bit greater than 7");
value & !(0x1 << bit)
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -119,3 +119,82 @@ fn test_set_hl_value_bit(opcode_variant: u8, expected: u8) {
.expect("failed to get memory value")
);
}
#[test_case(0x80, register::SingleEightBit::B, 0b11111110)]
#[test_case(0x88, register::SingleEightBit::B, 0b11111101)]
#[test_case(0x90, register::SingleEightBit::B, 0b11111011)]
#[test_case(0x98, register::SingleEightBit::B, 0b11110111)]
#[test_case(0xA0, register::SingleEightBit::B, 0b11101111)]
#[test_case(0xA8, register::SingleEightBit::B, 0b11011111)]
#[test_case(0xB0, register::SingleEightBit::B, 0b10111111)]
#[test_case(0xB8, register::SingleEightBit::B, 0b01111111)]
// Register C
#[test_case(0x81, register::SingleEightBit::C, 0b11111110)]
#[test_case(0x89, register::SingleEightBit::C, 0b11111101)]
#[test_case(0x91, register::SingleEightBit::C, 0b11111011)]
#[test_case(0x99, register::SingleEightBit::C, 0b11110111)]
#[test_case(0xA1, register::SingleEightBit::C, 0b11101111)]
#[test_case(0xA9, register::SingleEightBit::C, 0b11011111)]
#[test_case(0xB1, register::SingleEightBit::C, 0b10111111)]
#[test_case(0xB9, register::SingleEightBit::C, 0b01111111)]
// Register D
#[test_case(0x82, register::SingleEightBit::D, 0b11111110)]
#[test_case(0x8A, register::SingleEightBit::D, 0b11111101)]
#[test_case(0x92, register::SingleEightBit::D, 0b11111011)]
#[test_case(0x9A, register::SingleEightBit::D, 0b11110111)]
#[test_case(0xA2, register::SingleEightBit::D, 0b11101111)]
#[test_case(0xAA, register::SingleEightBit::D, 0b11011111)]
#[test_case(0xB2, register::SingleEightBit::D, 0b10111111)]
#[test_case(0xBA, register::SingleEightBit::D, 0b01111111)]
// Register E
#[test_case(0x83, register::SingleEightBit::E, 0b11111110)]
#[test_case(0x8B, register::SingleEightBit::E, 0b11111101)]
#[test_case(0x93, register::SingleEightBit::E, 0b11111011)]
#[test_case(0x9B, register::SingleEightBit::E, 0b11110111)]
#[test_case(0xA3, register::SingleEightBit::E, 0b11101111)]
#[test_case(0xAB, register::SingleEightBit::E, 0b11011111)]
#[test_case(0xB3, register::SingleEightBit::E, 0b10111111)]
#[test_case(0xBB, register::SingleEightBit::E, 0b01111111)]
// Register H
#[test_case(0x84, register::SingleEightBit::H, 0b11111110)]
#[test_case(0x8C, register::SingleEightBit::H, 0b11111101)]
#[test_case(0x94, register::SingleEightBit::H, 0b11111011)]
#[test_case(0x9C, register::SingleEightBit::H, 0b11110111)]
#[test_case(0xA4, register::SingleEightBit::H, 0b11101111)]
#[test_case(0xAC, register::SingleEightBit::H, 0b11011111)]
#[test_case(0xB4, register::SingleEightBit::H, 0b10111111)]
#[test_case(0xBC, register::SingleEightBit::H, 0b01111111)]
// Register L
#[test_case(0x85, register::SingleEightBit::L, 0b11111110)]
#[test_case(0x8D, register::SingleEightBit::L, 0b11111101)]
#[test_case(0x95, register::SingleEightBit::L, 0b11111011)]
#[test_case(0x9D, register::SingleEightBit::L, 0b11110111)]
#[test_case(0xA5, register::SingleEightBit::L, 0b11101111)]
#[test_case(0xAD, register::SingleEightBit::L, 0b11011111)]
#[test_case(0xB5, register::SingleEightBit::L, 0b10111111)]
#[test_case(0xBD, register::SingleEightBit::L, 0b01111111)]
// Register A
#[test_case(0x87, register::SingleEightBit::A, 0b11111110)]
#[test_case(0x8F, register::SingleEightBit::A, 0b11111101)]
#[test_case(0x97, register::SingleEightBit::A, 0b11111011)]
#[test_case(0x9F, register::SingleEightBit::A, 0b11110111)]
#[test_case(0xA7, register::SingleEightBit::A, 0b11101111)]
#[test_case(0xAF, register::SingleEightBit::A, 0b11011111)]
#[test_case(0xB7, register::SingleEightBit::A, 0b10111111)]
#[test_case(0xBF, register::SingleEightBit::A, 0b01111111)]
fn test_reset_register_bit(opcode_variant: u8, register: register::SingleEightBit, expected: u8) {
let mut processor = Processor::default();
processor.registers.set_single_8bit_register(register, 0xFF);
let data = [0xCB, opcode_variant, 0x02];
let (ins, extra_data) = Instruction::from_data(&data).expect("could not parse instruction");
assert_eq!(extra_data, &[0x02]);
processor.run_instruction(ins);
assert_eq!(
expected,
processor.registers.get_single_8bit_register(register)
);
}