diff --git a/src/cpus/m68k/execute.rs b/src/cpus/m68k/execute.rs index bbef921..f5ab250 100644 --- a/src/cpus/m68k/execute.rs +++ b/src/cpus/m68k/execute.rs @@ -224,12 +224,24 @@ impl M68k { self.timer.execute.start(); match self.decoder.instruction { Instruction::ABCD(src, dest) => { - let value = convert_from_bcd(self.get_target_value(src, Size::Byte, Used::Once)? as u8); - let existing = convert_from_bcd(self.get_target_value(dest, Size::Byte, Used::Twice)? as u8); - let result = existing.wrapping_add(value).wrapping_add(self.get_flag(Flags::Extend) as u8); - let carry = result > 99; - self.set_target_value(dest, convert_to_bcd(result) as u32, Size::Byte, Used::Twice)?; + let value = self.get_target_value(src, Size::Byte, Used::Once)?; + let existing = self.get_target_value(dest, Size::Byte, Used::Twice)?; + + let extend_flag = self.get_flag(Flags::Extend) as u32; + let src_parts = get_nibbles_from_byte(value); + let dest_parts = get_nibbles_from_byte(existing); + + let binary_result = value + existing + extend_flag; + let mut result = src_parts.1 + dest_parts.1 + extend_flag; + if result > 0x09 { result += 0x06 }; + result += src_parts.0 + dest_parts.0; + if result > 0x99 { result += 0x60 }; + let carry = (result & 0xFFFFFF00) != 0; + + self.set_target_value(dest, result, Size::Byte, Used::Twice)?; + self.set_flag(Flags::Negative, get_msb(result, Size::Byte)); self.set_flag(Flags::Zero, result == 0); + self.set_flag(Flags::Overflow, (!binary_result & result & 0x80) != 0); self.set_flag(Flags::Carry, carry); self.set_flag(Flags::Extend, carry); }, @@ -723,8 +735,11 @@ impl M68k { } self.state.d_reg[dest_l as usize] = (result & 0x00000000FFFFFFFF) as u32; }, - //Instruction::NBCD(Target) => { - //}, + Instruction::NBCD(dest) => { + let existing = self.get_target_value(dest, Size::Byte, Used::Twice)?; + let result = self.execute_sbcd(existing, 0)?; + self.set_target_value(dest, result, Size::Byte, Used::Twice)?; + }, Instruction::NEG(target, size) => { let original = self.get_target_value(target, size, Used::Twice)?; let (result, overflow) = overflowing_sub_signed_sized(0, original, size); @@ -857,14 +872,10 @@ impl M68k { self.state.status = Status::Stopped; }, Instruction::SBCD(src, dest) => { - let value = convert_from_bcd(self.get_target_value(src, Size::Byte, Used::Once)? as u8); - let existing = convert_from_bcd(self.get_target_value(dest, Size::Byte, Used::Twice)? as u8); - let result = existing.wrapping_sub(value).wrapping_sub(self.get_flag(Flags::Extend) as u8); - let borrow = existing < value; - self.set_target_value(dest, convert_to_bcd(result) as u32, Size::Byte, Used::Twice)?; - self.set_flag(Flags::Zero, result == 0); - self.set_flag(Flags::Carry, borrow); - self.set_flag(Flags::Extend, borrow); + let value = self.get_target_value(src, Size::Byte, Used::Once)?; + let existing = self.get_target_value(dest, Size::Byte, Used::Twice)?; + let result = self.execute_sbcd(value, existing)?; + self.set_target_value(dest, result, Size::Byte, Used::Twice)?; }, Instruction::SUB(src, dest, size) => { let value = self.get_target_value(src, size, Used::Once)?; @@ -947,6 +958,27 @@ impl M68k { Ok(()) } + fn execute_sbcd(&mut self, value: u32, existing: u32) -> Result { + let extend_flag = self.get_flag(Flags::Extend) as u32; + let src_parts = get_nibbles_from_byte(value); + let dest_parts = get_nibbles_from_byte(existing); + + let binary_result = existing.wrapping_sub(value).wrapping_sub(extend_flag); + let mut result = dest_parts.1.wrapping_sub(src_parts.1).wrapping_sub(extend_flag); + if (result & 0x1F) > 0x09 { result -= 0x06 }; + result = result.wrapping_add(dest_parts.0.wrapping_sub(src_parts.0)); + let carry = (result & 0x1FF) > 0x99; + if carry { result -= 0x60 }; + + self.set_flag(Flags::Negative, get_msb(result, Size::Byte)); + self.set_flag(Flags::Zero, (result & 0xFF) == 0); + self.set_flag(Flags::Overflow, (binary_result & !result & 0x80) != 0); + self.set_flag(Flags::Carry, carry); + self.set_flag(Flags::Extend, carry); + + Ok(result) + } + fn execute_movem(&mut self, target: Target, size: Size, dir: Direction, mask: u16) -> Result<(), Error> { let addr = self.get_target_address(target)?; @@ -1532,12 +1564,8 @@ fn rotate_operation(value: u32, size: Size, dir: ShiftDirection, use_extend: Opt } } -fn convert_from_bcd(value: u8) -> u8 { - (value >> 4) * 10 + (value & 0x0F) -} - -fn convert_to_bcd(value: u8) -> u8 { - (((value / 10) & 0x0F) << 4) | ((value % 10) & 0x0F) +fn get_nibbles_from_byte(value: u32) -> (u32, u32) { + (value & 0xF0, value & 0x0F) } fn get_value_sized(value: u32, size: Size) -> u32 { diff --git a/tests/harte_tests/run_all.sh b/tests/harte_tests/run_all.sh index 2ed8df4..df82279 100755 --- a/tests/harte_tests/run_all.sh +++ b/tests/harte_tests/run_all.sh @@ -2,9 +2,10 @@ COMMIT=$(git rev-parse HEAD) DATE=$(date --iso) LOCATION=$(dirname ${BASH_SOURCE[0]}) +RESULTS=latest.txt { cd $LOCATION - echo "Last run on $DATE at commit $COMMIT" | tee latest.txt - echo "" | tee -a latest.txt - cargo run -- -q --testsuite "../ProcessorTests/680x0/68000/uncompressed/" | tee -a latest.txt + echo "Last run on $DATE at commit $COMMIT" | tee $RESULTSt + echo "" | tee -a $RESULTS + cargo run -- -q --testsuite "../ProcessorTests/680x0/68000/uncompressed/" | tee -a $RESULTS } diff --git a/tests/harte_tests/run_exclude_addr.sh b/tests/harte_tests/run_exclude_addr.sh new file mode 100755 index 0000000..7ae4c26 --- /dev/null +++ b/tests/harte_tests/run_exclude_addr.sh @@ -0,0 +1,11 @@ +#!/bin/bash +COMMIT=$(git rev-parse HEAD) +DATE=$(date --iso) +LOCATION=$(dirname ${BASH_SOURCE[0]}) +RESULTS=latest-excluding-addr-error.txt +{ + cd $LOCATION + echo "Last run on $DATE at commit $COMMIT" | tee $RESULTS + echo "" | tee -a $RESULTS + cargo run -- -q --testsuite "../ProcessorTests/680x0/68000/uncompressed/" -e exclude-addr | tee -a $RESULTS +} diff --git a/todo.txt b/todo.txt index 32dd63b..862d391 100644 --- a/todo.txt +++ b/todo.txt @@ -3,6 +3,9 @@ Harte Tests: * for every failing test in MOVEfromSR, it's caused by an exception where at 0x7F3 it should be 0xF5, it's actually 0xE5, which is the READ/WRITE flag not set correctly (1 = READ) +* you could refactor the instruction loop into a series of functions, and test if there's a performance difference with and without #[inline(always)] + + * make it possible to compile without audio support (minifb frontend requires it atm) * I need some better function for dealing with memory, like a function that copies data with a loop, or allows offset reading of