From f0f9d5a6af33c8625cdc777839ef17bf52d619ea Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 8 Mar 2018 20:30:22 -0500 Subject: [PATCH 1/2] Corrects memptr leakage via BIT, and ld (de/bc/nn), A behaviour. --- .../Clock SignalTests/Z80MemptrTests.swift | 94 ++++++++++++++++--- .../Z80/Implementation/Z80Implementation.hpp | 6 +- Processors/Z80/Implementation/Z80Storage.cpp | 6 +- Processors/Z80/Implementation/Z80Storage.hpp | 2 + 4 files changed, 89 insertions(+), 19 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift index 63be6371a..804407f53 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -23,6 +23,16 @@ class Z80MemptrTests: XCTestCase { return machine.value(for: .memPtr) } + fileprivate func insert16(program: inout [UInt8], address: Int, offset: size_t) { + program[offset] = UInt8(address & 0x00ff) + program[offset + 1] = UInt8(address >> 8) + } + + /* + Re: comments below: + All the CPU chips tested give the same results except KP1858BM1 and T34BM1 slices noted as "BM1". + */ + // LD A, (addr) func testLDAnn() { // MEMPTR = addr+1 @@ -39,11 +49,40 @@ class Z80MemptrTests: XCTestCase { } } - /* TODO: - LD (addr),A - MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = A - Note for *BM1: MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = 0 - */ + // LD (bc/de),A, and LD (nn),A + func testLDrpA() { + // MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = A + // Note for *BM1: MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = 0 + let bcProgram: [UInt8] = [ + 0x02 + ] + let deProgram: [UInt8] = [ + 0x12 + ] + var nnProgram: [UInt8] = [ + 0x32, 0x00, 0x00 + ] + + for addr in 0 ..< 256 { + machine.setValue(UInt16(addr), for: .BC) + machine.setValue(UInt16(addr), for: .DE) + insert16(program: &nnProgram, address: addr, offset: 1) + + for a in 0 ..< 256 { + machine.setValue(UInt16(a), for: .A) + + let expectedResult = UInt16(((addr + 1) & 0xff) + (a << 8)) + + let bcResult = test(program: bcProgram, length: 7, initialValue: 0xffff) + let deResult = test(program: deProgram, length: 7, initialValue: 0xffff) + let nnResult = test(program: nnProgram, length: 13, initialValue: 0xffff) + + XCTAssertEqual(bcResult, expectedResult) + XCTAssertEqual(deResult, expectedResult) + XCTAssertEqual(nnResult, expectedResult) + } + } + } // LD A, (rp) func testLDArp() { @@ -68,19 +107,44 @@ class Z80MemptrTests: XCTestCase { } } - /* TODO: - LD (rp),A where rp -- BC or DE - MEMPTR_low = (rp + 1) & #FF, MEMPTR_hi = A - Note for *BM1: MEMPTR_low = (rp + 1) & #FF, MEMPTR_hi = 0 - */ + // LD (addr), rp + func testLDnnrp() { + // MEMPTR = addr + 1 + var ldnnhlBaseProgram: [UInt8] = [ + 0x22, 0x00, 0x00 + ] + var ldnnbcEDProgram: [UInt8] = [ + 0xed, 0x43, 0x00, 0x00 + ] + var ldnndeEDProgram: [UInt8] = [ + 0xed, 0x53, 0x00, 0x00 + ] + var ldnnhlEDProgram: [UInt8] = [ + 0xed, 0x63, 0x00, 0x00 + ] + var ldnnspEDProgram: [UInt8] = [ + 0xed, 0x73, 0x00, 0x00 + ] - /* TODO: - LD (addr), rp - MEMPTR = addr + 1 - */ + for addr in 0 ..< 65536 { + insert16(program: &ldnnhlBaseProgram, address: addr, offset: 1) + insert16(program: &ldnnbcEDProgram, address: addr, offset: 2) + insert16(program: &ldnndeEDProgram, address: addr, offset: 2) + insert16(program: &ldnnhlEDProgram, address: addr, offset: 2) + insert16(program: &ldnnspEDProgram, address: addr, offset: 2) + + let expectedResult = UInt16((addr + 1) & 0xffff) + + XCTAssertEqual(test(program: ldnnhlBaseProgram, length: 16, initialValue: expectedResult ^ 1), expectedResult) + XCTAssertEqual(test(program: ldnnbcEDProgram, length: 20, initialValue: expectedResult ^ 1), expectedResult) + XCTAssertEqual(test(program: ldnndeEDProgram, length: 20, initialValue: expectedResult ^ 1), expectedResult) + XCTAssertEqual(test(program: ldnnhlEDProgram, length: 20, initialValue: expectedResult ^ 1), expectedResult) + XCTAssertEqual(test(program: ldnnspEDProgram, length: 20, initialValue: expectedResult ^ 1), expectedResult) + } + } // LD rp, (addr) - func testLDnnrp() { + func testLDrpnn() { // MEMPTR = addr+1 var hlBaseProgram: [UInt8] = [ 0x22, 0x00, 0x00 diff --git a/Processors/Z80/Implementation/Z80Implementation.hpp b/Processors/Z80/Implementation/Z80Implementation.hpp index 7f1442a4c..ea4d02859 100644 --- a/Processors/Z80/Implementation/Z80Implementation.hpp +++ b/Processors/Z80/Implementation/Z80Implementation.hpp @@ -621,7 +621,7 @@ template < class T, case MicroOp::BIT: { uint8_t result = *static_cast(operation->source) & (1 << ((operation_ >> 3)&7)); - if(current_instruction_page_->is_indexed || ((operation_&0x08) == 7)) { + if(current_instruction_page_->is_indexed || ((operation_&0x07) == 6)) { bit53_result_ = memptr_.bytes.high; } else { bit53_result_ = *static_cast(operation->source); @@ -848,6 +848,10 @@ template < class T, memptr_.full = static_cast(*static_cast(operation->source) + (int8_t)temp8_); break; + case MicroOp::SetAddrAMemptr: + memptr_.full = static_cast(((*static_cast(operation->source) + 1)&0xff) + (a_ << 8)); + break; + case MicroOp::IndexedPlaceHolder: return; } diff --git a/Processors/Z80/Implementation/Z80Storage.cpp b/Processors/Z80/Implementation/Z80Storage.cpp index 15ebfdc50..7189ec72f 100644 --- a/Processors/Z80/Implementation/Z80Storage.cpp +++ b/Processors/Z80/Implementation/Z80Storage.cpp @@ -351,7 +351,7 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair InstructionTable base_program_table = { /* 0x00 NOP */ NOP, /* 0x01 LD BC, nn */ StdInstr(Read16Inc(pc_, bc_)), - /* 0x02 LD (BC), A */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Write3(memptr_, a_)), + /* 0x02 LD (BC), A */ StdInstr({MicroOp::SetAddrAMemptr, &bc_.full}, Write3(bc_, a_)), /* 0x03 INC BC; 0x04 INC B; 0x05 DEC B; 0x06 LD B, n */ INC_INC_DEC_LD(bc_, bc_.bytes.high), @@ -366,7 +366,7 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair /* 0x0f RRCA */ StdInstr({MicroOp::RRCA}), /* 0x10 DJNZ */ Instr(6, ReadInc(pc_, temp8_), {MicroOp::DJNZ}, InternalOperation(10), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}), /* 0x11 LD DE, nn */ StdInstr(Read16Inc(pc_, de_)), - /* 0x12 LD (DE), A */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Write3(memptr_, a_)), + /* 0x12 LD (DE), A */ StdInstr({MicroOp::SetAddrAMemptr, &de_.full}, Write3(de_, a_)), /* 0x13 INC DE; 0x14 INC D; 0x15 DEC D; 0x16 LD D, n */ INC_INC_DEC_LD(de_, de_.bytes.high), @@ -395,7 +395,7 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair /* 0x2f CPL */ StdInstr({MicroOp::CPL}), /* 0x30 JR NC */ JR(TestNC), /* 0x31 LD SP, nn */ StdInstr(Read16Inc(pc_, sp_)), - /* 0x32 LD (nn), A */ StdInstr(Read16Inc(pc_, temp16_), Write3(temp16_, a_)), + /* 0x32 LD (nn), A */ StdInstr(Read16Inc(pc_, temp16_), {MicroOp::SetAddrAMemptr, &temp16_.full}, Write3(temp16_, a_)), /* 0x33 INC SP */ Instr(8, {MicroOp::Increment16, &sp_.full}), /* 0x34 INC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Increment8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), /* 0x35 DEC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Decrement8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), diff --git a/Processors/Z80/Implementation/Z80Storage.hpp b/Processors/Z80/Implementation/Z80Storage.hpp index 9dd45179a..acc147c90 100644 --- a/Processors/Z80/Implementation/Z80Storage.hpp +++ b/Processors/Z80/Implementation/Z80Storage.hpp @@ -91,6 +91,8 @@ class ProcessorStorage { IndexedPlaceHolder, + SetAddrAMemptr, + Reset }; Type type; From 0e73ba4b3eda0d7424274e36e7ebde8de78518ef Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 9 Mar 2018 09:47:00 -0500 Subject: [PATCH 2/2] Introduces proper 5/3 SCF/CCF behaviour for the Z80. While also `const`ing a bunch of things. --- .../Z80/Implementation/Z80Implementation.hpp | 210 ++++++++++-------- Processors/Z80/Implementation/Z80Storage.hpp | 4 + 2 files changed, 120 insertions(+), 94 deletions(-) diff --git a/Processors/Z80/Implementation/Z80Implementation.hpp b/Processors/Z80/Implementation/Z80Implementation.hpp index ea4d02859..3b8e76c3d 100644 --- a/Processors/Z80/Implementation/Z80Implementation.hpp +++ b/Processors/Z80/Implementation/Z80Implementation.hpp @@ -54,9 +54,12 @@ template < class T, } while(true) { - const MicroOp *operation = scheduled_program_counter_; + const MicroOp *const operation = scheduled_program_counter_; scheduled_program_counter_++; +#define set_did_compute_flags() \ + flag_adjustment_history_ |= 1; + #define set_parity(v) \ parity_overflow_result_ = static_cast(v^1);\ parity_overflow_result_ ^= parity_overflow_result_ >> 4;\ @@ -90,6 +93,7 @@ template < class T, ir_.bytes.low = (ir_.bytes.low & 0x80) | ((ir_.bytes.low + current_instruction_page_->r_step) & 0x7f); pc_.full += pc_increment_ & static_cast(halt_mask_); scheduled_program_counter_ = current_instruction_page_->instructions[operation_ & halt_mask_]; + flag_adjustment_history_ <<= 1; break; case MicroOp::DecodeOperationNoRChange: refresh_addr_ = ir_; @@ -110,6 +114,7 @@ template < class T, case MicroOp::DisassembleAF: a_ = temp16_.bytes.high; set_flags(temp16_.bytes.low); + // break; // MARK: - Logical @@ -119,7 +124,8 @@ template < class T, set_parity(a_); \ half_carry_result_ = hf; \ subtract_flag_ = 0; \ - carry_result_ = 0; + carry_result_ = 0; \ + set_did_compute_flags(); case MicroOp::And: a_ &= *static_cast(operation->source); @@ -143,20 +149,31 @@ template < class T, subtract_flag_ = Flag::Subtract; half_carry_result_ = Flag::HalfCarry; bit53_result_ = a_; + set_did_compute_flags(); break; case MicroOp::CCF: half_carry_result_ = static_cast(carry_result_ << 4); carry_result_ ^= Flag::Carry; subtract_flag_ = 0; - bit53_result_ = a_; + if(flag_adjustment_history_&2) { + bit53_result_ = a_; + } else { + bit53_result_ |= a_; + } + set_did_compute_flags(); break; case MicroOp::SCF: carry_result_ = Flag::Carry; half_carry_result_ = 0; subtract_flag_ = 0; - bit53_result_ = a_; + if(flag_adjustment_history_&2) { + bit53_result_ = a_; + } else { + bit53_result_ |= a_; + } + set_did_compute_flags(); break; // MARK: - Flow control @@ -180,68 +197,69 @@ template < class T, half_carry_result_ = static_cast(half_result); \ parity_overflow_result_ = static_cast(overflow >> 5); \ subtract_flag_ = sub; \ - bit53_result_ = static_cast(b53); + bit53_result_ = static_cast(b53); \ + set_did_compute_flags(); case MicroOp::CP8: { - uint8_t value = *static_cast(operation->source); - int result = a_ - value; - int half_result = (a_&0xf) - (value&0xf); + const uint8_t value = *static_cast(operation->source); + const int result = a_ - value; + const int half_result = (a_&0xf) - (value&0xf); // overflow for a subtraction is when the signs were originally // different and the result is different again - int overflow = (value^a_) & (result^a_); + const int overflow = (value^a_) & (result^a_); // the 5 and 3 flags come from the operand, atypically set_arithmetic_flags(Flag::Subtract, value); } break; case MicroOp::SUB8: { - uint8_t value = *static_cast(operation->source); - int result = a_ - value; - int half_result = (a_&0xf) - (value&0xf); + const uint8_t value = *static_cast(operation->source); + const int result = a_ - value; + const int half_result = (a_&0xf) - (value&0xf); // overflow for a subtraction is when the signs were originally // different and the result is different again - int overflow = (value^a_) & (result^a_); + const int overflow = (value^a_) & (result^a_); a_ = static_cast(result); set_arithmetic_flags(Flag::Subtract, result); } break; case MicroOp::SBC8: { - uint8_t value = *static_cast(operation->source); - int result = a_ - value - (carry_result_ & Flag::Carry); - int half_result = (a_&0xf) - (value&0xf) - (carry_result_ & Flag::Carry); + const uint8_t value = *static_cast(operation->source); + const int result = a_ - value - (carry_result_ & Flag::Carry); + const int half_result = (a_&0xf) - (value&0xf) - (carry_result_ & Flag::Carry); // overflow for a subtraction is when the signs were originally // different and the result is different again - int overflow = (value^a_) & (result^a_); + const int overflow = (value^a_) & (result^a_); a_ = static_cast(result); set_arithmetic_flags(Flag::Subtract, result); } break; case MicroOp::ADD8: { - uint8_t value = *static_cast(operation->source); - int result = a_ + value; - int half_result = (a_&0xf) + (value&0xf); + const uint8_t value = *static_cast(operation->source); + const int result = a_ + value; + const int half_result = (a_&0xf) + (value&0xf); // overflow for addition is when the signs were originally // the same and the result is different - int overflow = ~(value^a_) & (result^a_); + const int overflow = ~(value^a_) & (result^a_); a_ = static_cast(result); set_arithmetic_flags(0, result); } break; case MicroOp::ADC8: { - uint8_t value = *static_cast(operation->source); - int result = a_ + value + (carry_result_ & Flag::Carry); - int half_result = (a_&0xf) + (value&0xf) + (carry_result_ & Flag::Carry); + const uint8_t value = *static_cast(operation->source); + const int result = a_ + value + (carry_result_ & Flag::Carry); + const int half_result = (a_&0xf) + (value&0xf) + (carry_result_ & Flag::Carry); // overflow for addition is when the signs were originally // the same and the result is different - int overflow = ~(value^a_) & (result^a_); + const int overflow = ~(value^a_) & (result^a_); a_ = static_cast(result); set_arithmetic_flags(0, result); @@ -250,9 +268,9 @@ template < class T, #undef set_arithmetic_flags case MicroOp::NEG: { - int overflow = (a_ == 0x80); - int result = -a_; - int halfResult = -(a_&0xf); + const int overflow = (a_ == 0x80); + const int result = -a_; + const int halfResult = -(a_&0xf); a_ = static_cast(result); bit53_result_ = sign_result_ = zero_result_ = a_; @@ -260,16 +278,17 @@ template < class T, subtract_flag_ = Flag::Subtract; carry_result_ = static_cast(result >> 8); half_carry_result_ = static_cast(halfResult); + set_did_compute_flags(); } break; case MicroOp::Increment8: { - uint8_t value = *static_cast(operation->source); - int result = value + 1; + const uint8_t value = *static_cast(operation->source); + const int result = value + 1; // with an increment, overflow occurs if the sign changes from // positive to negative - int overflow = (value ^ result) & ~value; - int half_result = (value&0xf) + 1; + const int overflow = (value ^ result) & ~value; + const int half_result = (value&0xf) + 1; *static_cast(operation->source) = static_cast(result); @@ -278,16 +297,17 @@ template < class T, half_carry_result_ = static_cast(half_result); parity_overflow_result_ = static_cast(overflow >> 5); subtract_flag_ = 0; + set_did_compute_flags(); } break; case MicroOp::Decrement8: { - uint8_t value = *static_cast(operation->source); - int result = value - 1; + const uint8_t value = *static_cast(operation->source); + const int result = value - 1; // with a decrement, overflow occurs if the sign changes from // negative to positive - int overflow = (value ^ result) & value; - int half_result = (value&0xf) - 1; + const int overflow = (value ^ result) & value; + const int half_result = (value&0xf) - 1; *static_cast(operation->source) = static_cast(result); @@ -296,28 +316,23 @@ template < class T, half_carry_result_ = static_cast(half_result); parity_overflow_result_ = static_cast(overflow >> 5); subtract_flag_ = Flag::Subtract; + set_did_compute_flags(); } break; case MicroOp::DAA: { - int lowNibble = a_ & 0xf; - int highNibble = a_ >> 4; + const int lowNibble = a_ & 0xf; + const int highNibble = a_ >> 4; int amountToAdd = 0; - if(carry_result_ & Flag::Carry) - { + if(carry_result_ & Flag::Carry) { amountToAdd = (lowNibble > 0x9 || (half_carry_result_ & Flag::HalfCarry)) ? 0x66 : 0x60; - } - else - { - if(half_carry_result_ & Flag::HalfCarry) - { + } else { + if(half_carry_result_ & Flag::HalfCarry) { if(lowNibble > 0x9) amountToAdd = (highNibble > 0x8) ? 0x66 : 0x06; else amountToAdd = (highNibble > 0x9) ? 0x66 : 0x06; - } - else - { + } else { if(lowNibble > 0x9) amountToAdd = (highNibble > 0x8) ? 0x66 : 0x06; else @@ -325,25 +340,18 @@ template < class T, } } - if(!(carry_result_ & Flag::Carry)) - { - if(lowNibble > 0x9) - { + if(!(carry_result_ & Flag::Carry)) { + if(lowNibble > 0x9) { if(highNibble > 0x8) carry_result_ = Flag::Carry; - } - else - { + } else { if(highNibble > 0x9) carry_result_ = Flag::Carry; } } - if(subtract_flag_) - { + if(subtract_flag_) { a_ -= amountToAdd; half_carry_result_ = ((half_carry_result_ & Flag::HalfCarry) && lowNibble < 0x6) ? Flag::HalfCarry : 0; - } - else - { + } else { a_ += amountToAdd; half_carry_result_ = (lowNibble > 0x9) ? Flag::HalfCarry : 0; } @@ -351,21 +359,23 @@ template < class T, sign_result_ = zero_result_ = bit53_result_ = a_; set_parity(a_); + set_did_compute_flags(); } break; // MARK: - 16-bit arithmetic case MicroOp::ADD16: { memptr_.full = *static_cast(operation->destination); - uint16_t sourceValue = *static_cast(operation->source); - uint16_t destinationValue = memptr_.full; - int result = sourceValue + destinationValue; - int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff); + const uint16_t sourceValue = *static_cast(operation->source); + const uint16_t destinationValue = memptr_.full; + const int result = sourceValue + destinationValue; + const int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff); bit53_result_ = static_cast(result >> 8); carry_result_ = static_cast(result >> 16); half_carry_result_ = static_cast(halfResult >> 8); subtract_flag_ = 0; + set_did_compute_flags(); *static_cast(operation->destination) = static_cast(result); memptr_.full++; @@ -373,12 +383,12 @@ template < class T, case MicroOp::ADC16: { memptr_.full = *static_cast(operation->destination); - uint16_t sourceValue = *static_cast(operation->source); - uint16_t destinationValue = memptr_.full; - int result = sourceValue + destinationValue + (carry_result_ & Flag::Carry); - int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff) + (carry_result_ & Flag::Carry); + const uint16_t sourceValue = *static_cast(operation->source); + const uint16_t destinationValue = memptr_.full; + const int result = sourceValue + destinationValue + (carry_result_ & Flag::Carry); + const int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff) + (carry_result_ & Flag::Carry); - int overflow = (result ^ destinationValue) & ~(destinationValue ^ sourceValue); + const int overflow = (result ^ destinationValue) & ~(destinationValue ^ sourceValue); bit53_result_ = sign_result_ = static_cast(result >> 8); @@ -387,6 +397,7 @@ template < class T, carry_result_ = static_cast(result >> 16); half_carry_result_ = static_cast(halfResult >> 8); parity_overflow_result_ = static_cast(overflow >> 13); + set_did_compute_flags(); *static_cast(operation->destination) = static_cast(result); memptr_.full++; @@ -394,15 +405,15 @@ template < class T, case MicroOp::SBC16: { memptr_.full = *static_cast(operation->destination); - uint16_t sourceValue = *static_cast(operation->source); - uint16_t destinationValue = memptr_.full; - int result = destinationValue - sourceValue - (carry_result_ & Flag::Carry); - int halfResult = (destinationValue&0xfff) - (sourceValue&0xfff) - (carry_result_ & Flag::Carry); + const uint16_t sourceValue = *static_cast(operation->source); + const uint16_t destinationValue = memptr_.full; + const int result = destinationValue - sourceValue - (carry_result_ & Flag::Carry); + const int halfResult = (destinationValue&0xfff) - (sourceValue&0xfff) - (carry_result_ & Flag::Carry); // subtraction, so parity rules are: // signs of operands were different, // sign of result is different - int overflow = (result ^ destinationValue) & (sourceValue ^ destinationValue); + const int overflow = (result ^ destinationValue) & (sourceValue ^ destinationValue); bit53_result_ = sign_result_ = static_cast(result >> 8); @@ -411,6 +422,7 @@ template < class T, carry_result_ = static_cast(result >> 16); half_carry_result_ = static_cast(halfResult >> 8); parity_overflow_result_ = static_cast(overflow >> 13); + set_did_compute_flags(); *static_cast(operation->destination) = static_cast(result); memptr_.full++; @@ -446,8 +458,8 @@ template < class T, } break; case MicroOp::ExAFAFDash: { - uint8_t a = a_; - uint8_t f = get_flags(); + const uint8_t a = a_; + const uint8_t f = get_flags(); set_flags(afDash_.bytes.low); a_ = afDash_.bytes.high; afDash_.bytes.high = a; @@ -476,11 +488,12 @@ template < class T, bc_.full--; \ de_.full += dir; \ hl_.full += dir; \ - uint8_t sum = a_ + temp8_; \ + const uint8_t sum = a_ + temp8_; \ bit53_result_ = static_cast((sum&0x8) | ((sum & 0x02) << 4)); \ subtract_flag_ = 0; \ half_carry_result_ = 0; \ - parity_overflow_result_ = bc_.full ? Flag::Parity : 0; + parity_overflow_result_ = bc_.full ? Flag::Parity : 0; \ + set_did_compute_flags(); case MicroOp::LDDR: { LDxR_STEP(-1); @@ -507,7 +520,7 @@ template < class T, bc_.full--; \ \ uint8_t result = a_ - temp8_; \ - uint8_t halfResult = (a_&0xf) - (temp8_&0xf); \ + const uint8_t halfResult = (a_&0xf) - (temp8_&0xf); \ \ parity_overflow_result_ = bc_.full ? Flag::Parity : 0; \ half_carry_result_ = halfResult; \ @@ -516,6 +529,7 @@ template < class T, \ result -= (halfResult >> 4)&1; \ bit53_result_ = static_cast((result&0x8) | ((result&0x2) << 4)); \ + set_did_compute_flags(); case MicroOp::CPDR: { CPxR_STEP(-1); @@ -546,7 +560,7 @@ template < class T, sign_result_ = zero_result_ = bit53_result_ = bc_.bytes.high; \ subtract_flag_ = (temp8_ >> 6) & Flag::Subtract; \ \ - int next_bc = bc_.bytes.low + dir; \ + const int next_bc = bc_.bytes.low + dir; \ int summation = temp8_ + (next_bc&0xff); \ \ if(summation > 0xff) { \ @@ -558,7 +572,8 @@ template < class T, } \ \ summation = (summation&7) ^ bc_.bytes.high; \ - set_parity(summation); + set_parity(summation); \ + set_did_compute_flags(); case MicroOp::INDR: { INxR_STEP(-1); @@ -598,7 +613,8 @@ template < class T, } \ \ summation = (summation&7) ^ bc_.bytes.high; \ - set_parity(summation); + set_parity(summation); \ + set_did_compute_flags(); case MicroOp::OUT_R: REPEAT(bc_.bytes.high); @@ -619,7 +635,7 @@ template < class T, // MARK: - Bit Manipulation case MicroOp::BIT: { - uint8_t result = *static_cast(operation->source) & (1 << ((operation_ >> 3)&7)); + const uint8_t result = *static_cast(operation->source) & (1 << ((operation_ >> 3)&7)); if(current_instruction_page_->is_indexed || ((operation_&0x07) == 6)) { bit53_result_ = memptr_.bytes.high; @@ -631,6 +647,7 @@ template < class T, half_carry_result_ = Flag::HalfCarry; subtract_flag_ = 0; parity_overflow_result_ = result ? 0 : Flag::Parity; + set_did_compute_flags(); } break; case MicroOp::RES: @@ -646,28 +663,29 @@ template < class T, #define set_rotate_flags() \ bit53_result_ = a_; \ carry_result_ = new_carry; \ - subtract_flag_ = half_carry_result_ = 0; + subtract_flag_ = half_carry_result_ = 0; \ + set_did_compute_flags(); case MicroOp::RLA: { - uint8_t new_carry = a_ >> 7; + const uint8_t new_carry = a_ >> 7; a_ = static_cast((a_ << 1) | (carry_result_ & Flag::Carry)); set_rotate_flags(); } break; case MicroOp::RRA: { - uint8_t new_carry = a_ & 1; + const uint8_t new_carry = a_ & 1; a_ = static_cast((a_ >> 1) | (carry_result_ << 7)); set_rotate_flags(); } break; case MicroOp::RLCA: { - uint8_t new_carry = a_ >> 7; + const uint8_t new_carry = a_ >> 7; a_ = static_cast((a_ << 1) | new_carry); set_rotate_flags(); } break; case MicroOp::RRCA: { - uint8_t new_carry = a_ & 1; + const uint8_t new_carry = a_ & 1; a_ = static_cast((a_ >> 1) | (new_carry << 7)); set_rotate_flags(); } break; @@ -678,7 +696,8 @@ template < class T, sign_result_ = zero_result_ = bit53_result_ = *static_cast(operation->source); \ set_parity(sign_result_); \ half_carry_result_ = 0; \ - subtract_flag_ = 0; + subtract_flag_ = 0; \ + set_did_compute_flags(); case MicroOp::RLC: carry_result_ = *static_cast(operation->source) >> 7; @@ -693,14 +712,14 @@ template < class T, break; case MicroOp::RL: { - uint8_t next_carry = *static_cast(operation->source) >> 7; + const uint8_t next_carry = *static_cast(operation->source) >> 7; *static_cast(operation->source) = static_cast((*static_cast(operation->source) << 1) | (carry_result_ & Flag::Carry)); carry_result_ = next_carry; set_shift_flags(); } break; case MicroOp::RR: { - uint8_t next_carry = *static_cast(operation->source); + const uint8_t next_carry = *static_cast(operation->source); *static_cast(operation->source) = static_cast((*static_cast(operation->source) >> 1) | (carry_result_ << 7)); carry_result_ = next_carry; set_shift_flags(); @@ -736,11 +755,12 @@ template < class T, subtract_flag_ = 0; \ half_carry_result_ = 0; \ set_parity(a_); \ - bit53_result_ = zero_result_ = sign_result_ = a_; + bit53_result_ = zero_result_ = sign_result_ = a_; \ + set_did_compute_flags(); case MicroOp::RRD: { memptr_.full = hl_.full + 1; - uint8_t low_nibble = a_ & 0xf; + const uint8_t low_nibble = a_ & 0xf; a_ = (a_ & 0xf0) | (temp8_ & 0xf); temp8_ = static_cast((temp8_ >> 4) | (low_nibble << 4)); set_decimal_rotate_flags(); @@ -748,7 +768,7 @@ template < class T, case MicroOp::RLD: { memptr_.full = hl_.full + 1; - uint8_t low_nibble = a_ & 0xf; + const uint8_t low_nibble = a_ & 0xf; a_ = (a_ & 0xf0) | (temp8_ >> 4); temp8_ = static_cast((temp8_ << 4) | low_nibble); set_decimal_rotate_flags(); @@ -784,12 +804,14 @@ template < class T, subtract_flag_ = half_carry_result_ = 0; sign_result_ = zero_result_ = bit53_result_ = *static_cast(operation->source); set_parity(sign_result_); + set_did_compute_flags(); break; case MicroOp::SetAFlags: subtract_flag_ = half_carry_result_ = 0; parity_overflow_result_ = iff2_ ? Flag::Parity : 0; sign_result_ = zero_result_ = bit53_result_ = a_; + set_did_compute_flags(); break; case MicroOp::SetZero: diff --git a/Processors/Z80/Implementation/Z80Storage.hpp b/Processors/Z80/Implementation/Z80Storage.hpp index acc147c90..0ef7244dd 100644 --- a/Processors/Z80/Implementation/Z80Storage.hpp +++ b/Processors/Z80/Implementation/Z80Storage.hpp @@ -134,6 +134,10 @@ class ProcessorStorage { uint8_t carry_result_; // the carry flag is set if bit 0 of carry_result_ is set uint8_t halt_mask_ = 0xff; + int flag_adjustment_history_ = 0; // a shifting record of whether each opcode set any flags; it turns out + // that knowledge of what the last opcode did is necessary to get bits 5 & 3 + // correct for SCF and CCF. + HalfCycles number_of_cycles_; enum Interrupt: uint8_t {