diff --git a/OSBindings/Mac/Clock SignalTests/68000Tests.mm b/OSBindings/Mac/Clock SignalTests/68000Tests.mm index 35e1735bc..979f9ca9a 100644 --- a/OSBindings/Mac/Clock SignalTests/68000Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000Tests.mm @@ -105,7 +105,7 @@ class RAM68000: public CPU::MC68000::BusHandler { case Microcycle::SelectByte: ram_[word_address % ram_.size()] = uint16_t( (cycle.value->halves.low << cycle.byte_shift()) | - (ram_[word_address] & cycle.untouched_byte_mask()) + (ram_[word_address % ram_.size()] & cycle.untouched_byte_mask()) ); break; } @@ -4103,6 +4103,68 @@ class CPU::MC68000::ProcessorStorageTests { XCTAssertEqual(74, _machine->get_cycle_count()); } +// MARK: NBCD + +- (void)performNBCDd1:(uint32_t)d1 ccr:(uint8_t)ccr { + _machine->set_program({ + 0x4801 // NBCD D1 + }); + auto state = _machine->get_processor_state(); + state.status |= ccr; + state.data[1] = d1; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + XCTAssertEqual(6, _machine->get_cycle_count()); +} + +- (void)testNBCD_Dn { + [self performNBCDd1:0x7a ccr:0]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], 0x20); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Carry | Flag::Overflow); +} + +- (void)testNBCD_Dn_extend { + [self performNBCDd1:0x1234567a ccr:Flag::Extend | Flag::Zero]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], 0x1234561f); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Carry | Flag::Overflow); +} + +- (void)testNBCD_Dn_zero { + [self performNBCDd1:0x12345600 ccr:Flag::Zero]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], 0x12345600); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); +} + +- (void)testNBCD_Dn_negative { + [self performNBCDd1:0x123456ff ccr:Flag::Extend | Flag::Zero]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], 0x1234569a); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Carry | Flag::Negative); +} + +- (void)testNBCD_Dn_XXXw { + _machine->set_program({ + 0x4838, 0x3000 // NBCD ($3000).w + }); + *_machine->ram_at(0x3000) = 0x0100; + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(16, _machine->get_cycle_count()); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x9900); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Carry | Flag::Negative); +} + // MARK: NEG - (void)performNEGb:(uint32_t)value { @@ -5038,6 +5100,78 @@ class CPU::MC68000::ProcessorStorageTests { XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::ConditionCodes); } +// MARK: SBCD + +- (void)performSBCDd1:(uint32_t)d1 d2:(uint32_t)d2 ccr:(uint8_t)ccr { + _machine->set_program({ + 0x8302 // SBCD D2, D1 + }); + auto state = _machine->get_processor_state(); + state.status |= ccr; + state.data[1] = d1; + state.data[2] = d2; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(6, _machine->get_cycle_count()); + XCTAssertEqual(state.data[2], d2); +} + +- (void)testSBCD_Dn { + [self performSBCDd1:0x12345689 d2:0xf745ff78 ccr:Flag::Zero]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], 0x12345611); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); +} + +- (void)testSBCD_Dn_zero { + [self performSBCDd1:0x123456ff d2:0xf745ffff ccr:Flag::Zero]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], 0x12345600); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); +} + +- (void)testSBCD_Dn_negative { + [self performSBCDd1:0x12345634 d2:0xf745ff45 ccr:Flag::Extend]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], 0x12345688); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Carry | Flag::Negative); +} + +- (void)testSBCD_Dn_overflow { + [self performSBCDd1:0x123456a9 d2:0xf745ffff ccr:Flag::Extend]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], 0x12345643); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Carry | Flag::Overflow); +} + +- (void)testSBCD_Dn_PreDec { + _machine->set_program({ + 0x830a // SBCD -(A2), -(A1) + }); + *_machine->ram_at(0x3000) = 0xa200; + *_machine->ram_at(0x4000) = 0x1900; + auto state = _machine->get_processor_state(); + state.address[1] = 0x3001; + state.address[2] = 0x4001; + state.status |= Flag::Extend; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(18, _machine->get_cycle_count()); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x8200); + XCTAssertEqual(*_machine->ram_at(0x4000), 0x1900); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative); +} + // MARK: SUB - (void)performSUBbIMM:(uint16_t)value d2:(uint32_t)d2 { diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 5e8c4bc86..5a11c3e63 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -376,7 +376,9 @@ template void Proces zero_result_ |= result & 0xff; extend_flag_ = carry_flag_ = uint_fast32_t(result & ~0xff); negative_flag_ = result & 0x80; - overflow_flag_ = add_overflow() & 0x80; + + const int unadjusted_result = destination + source + (extend_flag_ ? 1 : 0); + overflow_flag_ = ~unadjusted_result & result & 0x80; // Store the result. active_program_->destination->halves.low.halves.low = uint8_t(result); @@ -1507,17 +1509,18 @@ template void Proces #define sbcd() \ /* Perform the BCD arithmetic by evaluating the two nibbles separately. */ \ int result = (destination & 0xf) - (source & 0xf) - (extend_flag_ ? 1 : 0); \ - if(result > 0x09) result -= 0x06; \ - result += (destination & 0xf0) - (source & 0xf0); \ - if(result > 0x99) result -= 0x60; \ -\ - /* Set all flags essentially as if this were normal subtraction. */ \ - zero_result_ |= result & 0xff; \ - extend_flag_ = carry_flag_ = decltype(carry_flag_)(result & ~0xff); \ - negative_flag_ = result & 0x80; \ - overflow_flag_ = sub_overflow() & 0x80; \ -\ - /* Store the result. */ \ + if((result & 0x1f) > 0x09) result -= 0x06; \ + result += (destination & 0xf0) - (source & 0xf0); \ + if((result & 0x1ff) > 0x99) result -= 0x60; \ + \ + /* Set all flags essentially as if this were normal subtraction. */ \ + zero_result_ |= result & 0xff; \ + extend_flag_ = carry_flag_ = decltype(carry_flag_)(result & ~0xff); \ + negative_flag_ = result & 0x80; \ + const int unadjusted_result = destination - source - (extend_flag_ ? 1 : 0); \ + overflow_flag_ = unadjusted_result &~ result & 0x80; \ + \ + /* Store the result. */ \ active_program_->destination->halves.low.halves.low = uint8_t(result); /*