1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-09 17:29:36 +00:00

Clean up decimal ADC.

This commit is contained in:
Thomas Harte 2023-08-30 23:04:38 -04:00
parent 7b569b1a6c
commit 139a1a2acc
4 changed files with 59 additions and 9 deletions

31
Numeric/Carry.hpp Normal file
View File

@ -0,0 +1,31 @@
//
// Carry.hpp
// Clock Signal
//
// Created by Thomas Harte on 30/08/2023.
// Copyright © 2023 Thomas Harte. All rights reserved.
//
#ifndef Carry_hpp
#define Carry_hpp
namespace Numeric {
/// @returns @c true if there was carry out of @c bit when @c source1 and @c source2 were added, producing @c result.
template <int bit, typename IntT> bool carried_out(IntT source1, IntT source2, IntT result) {
// 0 and 0 => didn't.
// 0 and 1 or 1 and 0 => did if 0.
// 1 and 1 => did.
return IntT(1 << bit) & (source1 | source2) & ((source1 & source2) | ~result);
}
/// @returns @c true if there was carry into @c bit when @c source1 and @c source2 were added, producing @c result.
template <int bit, typename IntT> bool carried_in(IntT source1, IntT source2, IntT result) {
// 0 and 0 or 1 and 1 => did if 1
// 0 and 1 or 1 and 0 => did if 0
return IntT(1 << bit) & (source1 ^ source2 ^ result);
}
}
#endif /* Carry_hpp */

View File

@ -1101,6 +1101,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
4281572E2AA0334300E16AA1 /* Carry.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Carry.hpp; sourceTree = "<group>"; };
428168372A16C25C008ECD27 /* LineLayout.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LineLayout.hpp; sourceTree = "<group>"; };
428168392A37AFB4008ECD27 /* DispatcherTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DispatcherTests.mm; sourceTree = "<group>"; };
42AD552E2A0C4D5000ACE410 /* 68000.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 68000.hpp; sourceTree = "<group>"; };
@ -3313,6 +3314,7 @@
4B66E1A8297719270057ED0F /* NumericCoder.hpp */,
4BB5B995281B1D3E00522DA9 /* RegisterSizes.hpp */,
4BFEA2F12682A90200EBF94C /* Sizes.hpp */,
4281572E2AA0334300E16AA1 /* Carry.hpp */,
);
name = Numeric;
path = ../../Numeric;

View File

@ -15,6 +15,7 @@
#include "../6502Esque/6502Esque.hpp"
#include "../6502Esque/Implementation/LazyFlags.hpp"
#include "../../Numeric/Carry.hpp"
#include "../../Numeric/RegisterSizes.hpp"
#include "../../ClockReceiver/ClockReceiver.hpp"

View File

@ -317,18 +317,34 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
case OperationADC:
if(flags_.decimal && has_decimal_mode(personality)) {
const uint16_t decimalResult = uint16_t(a_) + uint16_t(operand_) + uint16_t(flags_.carry);
uint8_t result = a_ + operand_ + flags_.carry;
flags_.zero_result = result;
flags_.carry = Numeric::carried_out<7>(a_, operand_, result);
uint8_t low_nibble = (a_ & 0xf) + (operand_ & 0xf) + flags_.carry;
if(low_nibble >= 0xa) low_nibble = ((low_nibble + 0x6) & 0xf) + 0x10;
uint16_t result = uint16_t(a_ & 0xf0) + uint16_t(operand_ & 0xf0) + uint16_t(low_nibble);
// The following effects the rule that only a single bit of carry can flow from the
// bottom nibble to the top: if that carry already happened, fix up the bottom without
// permitting another; otherwise if a fix up is required anyway due to the low digit nibble
// being out of range, permit the carry to happen (and check whether carry then left bit 7).
if(Numeric::carried_in<4>(a_, operand_, result)) {
result = (result & 0xf0) | ((result + 0x06) & 0x0f);
} else if((result & 0xf) > 0x9) {
flags_.carry |= result >= 0x100 - 0x6;
result += 0x06;
}
// 6502 quirk: N and V are set before the full result is computed but after the low nibble
// has been corrected.
flags_.negative_result = uint8_t(result);
flags_.overflow = (( (result^a_)&(result^operand_) )&0x80) >> 1;
if(result >= 0xa0) result += 0x60;
flags_.overflow = (( (result ^ a_) & (result ^ operand_) ) & 0x80) >> 1;
flags_.carry = (result >> 8) ? 1 : 0;
a_ = uint8_t(result);
flags_.zero_result = uint8_t(decimalResult);
if(Numeric::carried_out<7>(a_, operand_, result)) {
result += 0x60;
} else if (result >= 0xa0) {
flags_.carry = 1; // There'll now definitely be carry.
result += 0x60;
}
a_ = result;
if(is_65c02(personality)) {
flags_.set_nz(a_);