Compare commits
1 Commits
master
...
old-bit-ma
Author | SHA1 | Date |
---|---|---|
Nick Krichevsky | fa7528279b |
|
@ -9,4 +9,8 @@ pub enum BitManipulationInstruction {
|
||||||
SetHLValueBit {
|
SetHLValueBit {
|
||||||
bit: u8,
|
bit: u8,
|
||||||
},
|
},
|
||||||
|
ResetRegisterBit {
|
||||||
|
register: register::SingleEightBit,
|
||||||
|
bit: u8,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{unparsed::Opcode, OpcodeParser, ParseResult};
|
use super::{unparsed::Opcode, OpcodeParser, OrParse, ParseResult};
|
||||||
use crate::{
|
use crate::{
|
||||||
cpu::{
|
cpu::{
|
||||||
instructions::{manip::BitManipulationInstruction, Instruction},
|
instructions::{manip::BitManipulationInstruction, Instruction},
|
||||||
|
@ -19,7 +19,7 @@ impl OpcodeParser for Parser {
|
||||||
fn parse_opcode(data: &View) -> ParseResult {
|
fn parse_opcode(data: &View) -> ParseResult {
|
||||||
let opcode = parse::get_opcode_from_data(data);
|
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))
|
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> {
|
fn operand_for_opcode(opcode: u16) -> Result<OpcodeOperand, parse::Error> {
|
||||||
let register_nibble = opcode & 0x000F;
|
let register_nibble = opcode & 0x000F;
|
||||||
match register_nibble {
|
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
|
// Given the range we've constrained to, this has to be able to fit in 8 bits
|
||||||
Ok(bit.try_into().unwrap())
|
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())
|
||||||
|
}
|
||||||
|
|
|
@ -58,6 +58,17 @@ impl Run for BitManipulationInstruction {
|
||||||
|
|
||||||
Ok(Cycles(16))
|
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)
|
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
|
@ -119,3 +119,82 @@ fn test_set_hl_value_bit(opcode_variant: u8, expected: u8) {
|
||||||
.expect("failed to get memory value")
|
.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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue