From 18e8d6ce06237f2be158e0419535f32f2d905a89 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 5 Oct 2020 22:23:33 -0400 Subject: [PATCH] Makes an effort to factor out the 6502's [lazy] flags. This is preparatory to deciding which instructions, if any, are worth factoring out. --- .../Clock Signal.xcodeproj/project.pbxproj | 48 +++- Processors/6502/6502.hpp | 20 +- Processors/6502/AllRAM/6502AllRAM.hpp | 2 +- .../Implementation/6502Implementation.hpp | 263 +++++++++--------- .../6502/Implementation/6502Storage.cpp | 6 - .../6502/Implementation/6502Storage.hpp | 4 +- Processors/{ => 6502Esque}/6502Esque.hpp | 17 ++ Processors/{ => 6502Esque}/6502Selector.hpp | 4 +- .../6502Esque/Implementation/LazyFlags.hpp | 66 +++++ Processors/6502Esque/README.md | 3 + Processors/65816/65816.hpp | 2 +- .../Implementation/65816Implementation.hpp | 6 +- 12 files changed, 262 insertions(+), 179 deletions(-) rename Processors/{ => 6502Esque}/6502Esque.hpp (89%) rename Processors/{ => 6502Esque}/6502Selector.hpp (96%) create mode 100644 Processors/6502Esque/Implementation/LazyFlags.hpp create mode 100644 Processors/6502Esque/README.md diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index b78dc0fda..30c4d4bd2 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -210,9 +210,9 @@ 4B4B1A3D200198CA00A0F866 /* KonamiSCC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4B1A3A200198C900A0F866 /* KonamiSCC.cpp */; }; 4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */; }; 4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */; }; - 4B4DEBED2522C03F004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEBEC2522C03F004583AC /* 65816Base.cpp */; }; - 4B4DEBEE2522C03F004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEBEC2522C03F004583AC /* 65816Base.cpp */; }; - 4B4DEBEF2522C03F004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEBEC2522C03F004583AC /* 65816Base.cpp */; }; + 4B4DEC06252BFA56004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEC05252BFA56004583AC /* 65816Base.cpp */; }; + 4B4DEC07252BFA56004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEC05252BFA56004583AC /* 65816Base.cpp */; }; + 4B4DEC08252BFA56004583AC /* 65816Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DEC05252BFA56004583AC /* 65816Base.cpp */; }; 4B50AF80242817F40099BBD7 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B50AF7F242817F40099BBD7 /* QuartzCore.framework */; }; 4B54C0BC1F8D8E790050900F /* KeyboardMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */; }; 4B54C0BF1F8D8F450050900F /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0BD1F8D8F450050900F /* Keyboard.cpp */; }; @@ -1122,7 +1122,11 @@ 4B4DC8271D2C2470003C5BF8 /* C1540.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = C1540.hpp; sourceTree = ""; }; 4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SerialBus.cpp; sourceTree = ""; }; 4B4DC82A1D2C27A4003C5BF8 /* SerialBus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SerialBus.hpp; sourceTree = ""; }; - 4B4DEBEC2522C03F004583AC /* 65816Base.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = 65816Base.cpp; path = ../../Processors/65816/Implementation/65816Base.cpp; sourceTree = ""; }; + 4B4DEC04252BFA56004583AC /* 65816Implementation.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 65816Implementation.hpp; sourceTree = ""; }; + 4B4DEC05252BFA56004583AC /* 65816Base.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 65816Base.cpp; sourceTree = ""; }; + 4B4DEC16252BFA9C004583AC /* 6502Selector.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502Selector.hpp; sourceTree = ""; }; + 4B4DEC18252BFA9C004583AC /* 6502Esque.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502Esque.hpp; sourceTree = ""; }; + 4B4DEC19252BFB5A004583AC /* LazyFlags.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LazyFlags.hpp; sourceTree = ""; }; 4B4F2B7024DF99D4000DA6B0 /* CSScanTarget+CppScanTarget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CSScanTarget+CppScanTarget.h"; sourceTree = ""; }; 4B50AF7F242817F40099BBD7 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 4B51F70920A521D700AFA2C1 /* Source.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Source.hpp; sourceTree = ""; }; @@ -1346,9 +1350,6 @@ 4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Storage.hpp; sourceTree = ""; }; 4BAF2B4C2004580C00480230 /* DMK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DMK.cpp; sourceTree = ""; }; 4BAF2B4D2004580C00480230 /* DMK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DMK.hpp; sourceTree = ""; }; - 4BB023FF25212888009F8D90 /* 65816Implementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = 65816Implementation.hpp; path = ../../Processors/65816/Implementation/65816Implementation.hpp; sourceTree = ""; }; - 4BB0240425229C6E009F8D90 /* 6502Esque.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = 6502Esque.hpp; sourceTree = ""; }; - 4BB024092522B7BE009F8D90 /* 6502Selector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = 6502Selector.hpp; sourceTree = ""; }; 4BB06B211F316A3F00600C7A /* ForceInline.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ForceInline.hpp; sourceTree = ""; }; 4BB0A6592044FD3000FB3688 /* SN76489.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SN76489.cpp; sourceTree = ""; }; 4BB0A65A2044FD3000FB3688 /* SN76489.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SN76489.hpp; sourceTree = ""; }; @@ -2463,6 +2464,24 @@ path = 1540; sourceTree = ""; }; + 4B4DEC15252BFA9C004583AC /* 6502Esque */ = { + isa = PBXGroup; + children = ( + 4B4DEC18252BFA9C004583AC /* 6502Esque.hpp */, + 4B4DEC16252BFA9C004583AC /* 6502Selector.hpp */, + 4B4DEC17252BFA9C004583AC /* Implementation */, + ); + path = 6502Esque; + sourceTree = ""; + }; + 4B4DEC17252BFA9C004583AC /* Implementation */ = { + isa = PBXGroup; + children = ( + 4B4DEC19252BFB5A004583AC /* LazyFlags.hpp */, + ); + path = Implementation; + sourceTree = ""; + }; 4B51F70820A521D700AFA2C1 /* Activity */ = { isa = PBXGroup; children = ( @@ -3337,8 +3356,6 @@ 4BB73E951B587A5100552FC2 = { isa = PBXGroup; children = ( - 4B4DEBEC2522C03F004583AC /* 65816Base.cpp */, - 4BB023FF25212888009F8D90 /* 65816Implementation.hpp */, 4B51F70820A521D700AFA2C1 /* Activity */, 4B8944E2201967B4007DE474 /* Analyser */, 4BB73EA01B587A5100552FC2 /* Clock Signal */, @@ -3496,11 +3513,10 @@ isa = PBXGroup; children = ( 4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */, - 4BB0240425229C6E009F8D90 /* 6502Esque.hpp */, - 4BB024092522B7BE009F8D90 /* 6502Selector.hpp */, 4BFCA1221ECBDCAF00AC40C1 /* AllRAMProcessor.hpp */, 4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */, 4B1414561B58879D00E04248 /* 6502 */, + 4B4DEC15252BFA9C004583AC /* 6502Esque */, 4BF8D4CC251C0C9C00BBE21B /* 65816 */, 4BFF1D332233778C00838EA1 /* 68000 */, 4B77069E1EC9045B0053B588 /* Z80 */, @@ -3921,8 +3937,10 @@ 4BF8D4D2251C0D9F00BBE21B /* Implementation */ = { isa = PBXGroup; children = ( - 4BF8D4D3251C0D9F00BBE21B /* 65816Storage.hpp */, + 4B4DEC05252BFA56004583AC /* 65816Base.cpp */, 4BF8D4D4251C11DD00BBE21B /* 65816Storage.cpp */, + 4B4DEC04252BFA56004583AC /* 65816Implementation.hpp */, + 4BF8D4D3251C0D9F00BBE21B /* 65816Storage.hpp */, ); path = Implementation; sourceTree = ""; @@ -4503,7 +4521,7 @@ 4BDACBED22FFA5D20045EF7E /* ncr5380.cpp in Sources */, 4BC131772346DE9100E4FF3D /* StaticAnalyser.cpp in Sources */, 4B055ACF1FAE9B030060FFFF /* SoundGenerator.cpp in Sources */, - 4B4DEBEF2522C03F004583AC /* 65816Base.cpp in Sources */, + 4B4DEC08252BFA56004583AC /* 65816Base.cpp in Sources */, 4B894519201967B4007DE474 /* ConfidenceCounter.cpp in Sources */, 4B055AEE1FAE9BBF0060FFFF /* Keyboard.cpp in Sources */, 4B055AED1FAE9BA20060FFFF /* Z80Storage.cpp in Sources */, @@ -4786,7 +4804,7 @@ 4BEBFB4D2002C4BF000708CC /* MSXDSK.cpp in Sources */, 4BBFBB6C1EE8401E00C01E7A /* ZX8081.cpp in Sources */, 4B83348A1F5DB94B0097E338 /* IRQDelegatePortHandler.cpp in Sources */, - 4B4DEBED2522C03F004583AC /* 65816Base.cpp in Sources */, + 4B4DEC06252BFA56004583AC /* 65816Base.cpp in Sources */, 4B894524201967B4007DE474 /* Tape.cpp in Sources */, 4B7136891F78725F008B8ED9 /* Shifter.cpp in Sources */, 4BDB61EB2032806E0048AF91 /* CSAtari2600.mm in Sources */, @@ -4934,7 +4952,7 @@ 4B778F4123A5F19A0000D260 /* MemoryPacker.cpp in Sources */, 4B778F4423A5F1BE0000D260 /* CommodoreGCR.cpp in Sources */, 4B778EF923A5EB740000D260 /* MSA.cpp in Sources */, - 4B4DEBEE2522C03F004583AC /* 65816Base.cpp in Sources */, + 4B4DEC07252BFA56004583AC /* 65816Base.cpp in Sources */, 4B778F2323A5EDE40000D260 /* Tape.cpp in Sources */, 4B778F4F23A5F21C0000D260 /* StaticAnalyser.cpp in Sources */, 4B778EEF23A5D6680000D260 /* AsyncTaskQueue.cpp in Sources */, diff --git a/Processors/6502/6502.hpp b/Processors/6502/6502.hpp index fe69490e9..7b4eb55a8 100644 --- a/Processors/6502/6502.hpp +++ b/Processors/6502/6502.hpp @@ -13,16 +13,19 @@ #include #include +#include "../6502Esque/6502Esque.hpp" +#include "../6502Esque/Implementation/LazyFlags.hpp" #include "../RegisterSizes.hpp" #include "../../ClockReceiver/ClockReceiver.hpp" -#include "../6502Esque.hpp" namespace CPU { namespace MOS6502 { +// Adopt a bunch of things from MOS6502Esque. using BusOperation = CPU::MOS6502Esque::BusOperation; using BusHandler = CPU::MOS6502Esque::BusHandler; using Register = CPU::MOS6502Esque::Register; +using Flag = CPU::MOS6502Esque::Flag; /* The list of 6502 variants supported by this implementation. @@ -40,21 +43,6 @@ enum Personality { #define has_bbrbbsrmbsmb(p) ((p) >= Personality::PRockwell65C02) #define has_stpwai(p) ((p) >= Personality::PWDC65C02) -/* - Flags as defined on the 6502; can be used to decode the result of @c get_value_of_register(Flags) or to form a value for - the corresponding set. -*/ -enum Flag: uint8_t { - Sign = 0x80, - Overflow = 0x40, - Always = 0x20, - Break = 0x10, - Decimal = 0x08, - Interrupt = 0x04, - Zero = 0x02, - Carry = 0x01 -}; - /*! An opcode that is guaranteed to cause the CPU to jam. */ diff --git a/Processors/6502/AllRAM/6502AllRAM.hpp b/Processors/6502/AllRAM/6502AllRAM.hpp index 9d7a6cd1d..f6a354f78 100644 --- a/Processors/6502/AllRAM/6502AllRAM.hpp +++ b/Processors/6502/AllRAM/6502AllRAM.hpp @@ -9,7 +9,7 @@ #ifndef MOS6502AllRAM_cpp #define MOS6502AllRAM_cpp -#include "../../6502Selector.hpp" +#include "../../6502Esque/6502Selector.hpp" #include "../../AllRAMProcessor.hpp" namespace CPU { diff --git a/Processors/6502/Implementation/6502Implementation.hpp b/Processors/6502/Implementation/6502Implementation.hpp index 773edbb00..673970e31 100644 --- a/Processors/6502/Implementation/6502Implementation.hpp +++ b/Processors/6502/Implementation/6502Implementation.hpp @@ -13,7 +13,7 @@ */ template void Processor::run_for(const Cycles cycles) { - static uint8_t throwaway_target; + uint8_t throwaway_target; // These plus program below act to give the compiler permission to update these values // without touching the class storage (i.e. it explicitly says they need be completely up @@ -42,7 +42,7 @@ template void Proces #define bus_access() \ interrupt_requests_ = (interrupt_requests_ & ~InterruptRequestFlags::IRQ) | irq_request_history_; \ - irq_request_history_ = irq_line_ & inverse_interrupt_flag_; \ + irq_request_history_ = irq_line_ & flags_.inverse_interrupt; \ number_of_cycles -= bus_handler_.perform_bus_operation(nextBusOperation, busAddress, busValue); \ nextBusOperation = BusOperation::None; \ if(number_of_cycles <= Cycles(0)) break; @@ -70,7 +70,7 @@ template void Proces // Deal with a potential WAI state, if this 6502 implements WAI. while(has_stpwai(personality) && wait_is_active_ && number_of_cycles > Cycles(0)) { number_of_cycles -= bus_handler_.perform_bus_operation(BusOperation::Ready, busAddress, busValue); - interrupt_requests_ |= (irq_line_ & inverse_interrupt_flag_); + interrupt_requests_ |= (irq_line_ & flags_.inverse_interrupt); if(interrupt_requests_ & InterruptRequestFlags::NMI || irq_line_) { wait_is_active_ = false; checkSchedule(); @@ -167,25 +167,25 @@ template void Proces case CycleReadVectorLow: read_mem(pc_.halves.low, nextAddress.full); break; case CycleReadVectorHigh: read_mem(pc_.halves.high, nextAddress.full+1); break; case OperationSetIRQFlags: - inverse_interrupt_flag_ = 0; - if(is_65c02(personality)) decimal_flag_ = false; + flags_.inverse_interrupt = 0; + if(is_65c02(personality)) flags_.decimal = 0; continue; case OperationSetNMIRSTFlags: - if(is_65c02(personality)) decimal_flag_ = false; + if(is_65c02(personality)) flags_.decimal = 0; continue; - case CyclePullPCL: s_++; read_mem(pc_.halves.low, s_ | 0x100); break; - case CyclePullPCH: s_++; read_mem(pc_.halves.high, s_ | 0x100); break; - case CyclePullA: s_++; read_mem(a_, s_ | 0x100); break; - case CyclePullX: s_++; read_mem(x_, s_ | 0x100); break; - case CyclePullY: s_++; read_mem(y_, s_ | 0x100); break; - case CyclePullOperand: s_++; read_mem(operand_, s_ | 0x100); break; - case OperationSetFlagsFromOperand: set_flags(operand_); continue; - case OperationSetOperandFromFlagsWithBRKSet: operand_ = get_flags() | Flag::Break; continue; - case OperationSetOperandFromFlags: operand_ = get_flags(); continue; - case OperationSetFlagsFromA: zero_result_ = negative_result_ = a_; continue; - case OperationSetFlagsFromX: zero_result_ = negative_result_ = x_; continue; - case OperationSetFlagsFromY: zero_result_ = negative_result_ = y_; continue; + case CyclePullPCL: s_++; read_mem(pc_.halves.low, s_ | 0x100); break; + case CyclePullPCH: s_++; read_mem(pc_.halves.high, s_ | 0x100); break; + case CyclePullA: s_++; read_mem(a_, s_ | 0x100); break; + case CyclePullX: s_++; read_mem(x_, s_ | 0x100); break; + case CyclePullY: s_++; read_mem(y_, s_ | 0x100); break; + case CyclePullOperand: s_++; read_mem(operand_, s_ | 0x100); break; + case OperationSetFlagsFromOperand: set_flags(operand_); continue; + case OperationSetOperandFromFlagsWithBRKSet: operand_ = flags_.get() | Flag::Break; continue; + case OperationSetOperandFromFlags: operand_ = flags_.get(); continue; + case OperationSetFlagsFromA: flags_.set_nz(a_); continue; + case OperationSetFlagsFromX: flags_.set_nz(x_); continue; + case OperationSetFlagsFromY: flags_.set_nz(y_); continue; case CycleIncrementPCAndReadStack: pc_.full++; throwaway_read(s_ | 0x100); break; case CycleReadPCLFromAddress: read_mem(pc_.halves.low, address_.full); break; @@ -216,17 +216,17 @@ template void Proces // MARK: - Bitwise - case OperationORA: a_ |= operand_; negative_result_ = zero_result_ = a_; continue; - case OperationAND: a_ &= operand_; negative_result_ = zero_result_ = a_; continue; - case OperationEOR: a_ ^= operand_; negative_result_ = zero_result_ = a_; continue; + case OperationORA: a_ |= operand_; flags_.set_nz(a_); continue; + case OperationAND: a_ &= operand_; flags_.set_nz(a_); continue; + case OperationEOR: a_ ^= operand_; flags_.set_nz(a_); continue; // MARK: - Load and Store - case OperationLDA: a_ = negative_result_ = zero_result_ = operand_; continue; - case OperationLDX: x_ = negative_result_ = zero_result_ = operand_; continue; - case OperationLDY: y_ = negative_result_ = zero_result_ = operand_; continue; - case OperationLAX: a_ = x_ = negative_result_ = zero_result_ = operand_; continue; - case OperationCopyOperandToA: a_ = operand_; continue; + case OperationLDA: flags_.set_nz(a_ = operand_); continue; + case OperationLDX: flags_.set_nz(x_ = operand_); continue; + case OperationLDY: flags_.set_nz(y_ = operand_); continue; + case OperationLAX: flags_.set_nz(a_ = x_ = operand_); continue; + case OperationCopyOperandToA: a_ = operand_; continue; case OperationSTA: operand_ = a_; continue; case OperationSTX: operand_ = x_; continue; @@ -240,43 +240,43 @@ template void Proces case OperationLXA: a_ = x_ = (a_ | 0xee) & operand_; - negative_result_ = zero_result_ = a_; + flags_.set_nz(a_); continue; // MARK: - Compare case OperationCMP: { const uint16_t temp16 = a_ - operand_; - negative_result_ = zero_result_ = uint8_t(temp16); - carry_flag_ = ((~temp16) >> 8)&1; + flags_.set_nz(uint8_t(temp16)); + flags_.carry = ((~temp16) >> 8)&1; } continue; case OperationCPX: { const uint16_t temp16 = x_ - operand_; - negative_result_ = zero_result_ = uint8_t(temp16); - carry_flag_ = ((~temp16) >> 8)&1; + flags_.set_nz(uint8_t(temp16)); + flags_.carry = ((~temp16) >> 8)&1; } continue; case OperationCPY: { const uint16_t temp16 = y_ - operand_; - negative_result_ = zero_result_ = uint8_t(temp16); - carry_flag_ = ((~temp16) >> 8)&1; + flags_.set_nz(uint8_t(temp16)); + flags_.carry = ((~temp16) >> 8)&1; } continue; // MARK: - BIT, TSB, TRB case OperationBIT: - zero_result_ = operand_ & a_; - negative_result_ = operand_; - overflow_flag_ = operand_&Flag::Overflow; + flags_.zero_result = operand_ & a_; + flags_.negative_result = operand_; + flags_.overflow = operand_ & Flag::Overflow; continue; case OperationBITNoNV: - zero_result_ = operand_ & a_; + flags_.zero_result = operand_ & a_; continue; case OperationTRB: - zero_result_ = operand_ & a_; + flags_.zero_result = operand_ & a_; operand_ &= ~a_; continue; case OperationTSB: - zero_result_ = operand_ & a_; + flags_.zero_result = operand_ & a_; operand_ |= a_; continue; @@ -295,8 +295,8 @@ template void Proces operand_++; [[fallthrough]]; case OperationSBC: - if(decimal_flag_ && has_decimal_mode(personality)) { - const uint16_t notCarry = carry_flag_ ^ 0x1; + if(flags_.decimal && has_decimal_mode(personality)) { + const uint16_t notCarry = flags_.carry ^ 0x1; const uint16_t decimalResult = uint16_t(a_) - uint16_t(operand_) - notCarry; uint16_t temp16; @@ -305,17 +305,17 @@ template void Proces temp16 = (temp16&0x0f) | ((temp16 > 0x0f) ? 0xfff0 : 0x00); temp16 += (a_&0xf0) - (operand_&0xf0); - overflow_flag_ = ( ( (decimalResult^a_)&(~decimalResult^operand_) )&0x80) >> 1; - negative_result_ = uint8_t(temp16); - zero_result_ = uint8_t(decimalResult); + flags_.overflow = ( ( (decimalResult^a_)&(~decimalResult^operand_) )&0x80) >> 1; + flags_.negative_result = uint8_t(temp16); + flags_.zero_result = uint8_t(decimalResult); if(temp16 > 0xff) temp16 -= 0x60; - carry_flag_ = (temp16 > 0xff) ? 0 : Flag::Carry; + flags_.carry = (temp16 > 0xff) ? 0 : Flag::Carry; a_ = uint8_t(temp16); if(is_65c02(personality)) { - negative_result_ = zero_result_ = a_; + flags_.set_nz(a_); read_mem(operand_, address_.full); break; } @@ -326,30 +326,30 @@ template void Proces [[fallthrough]]; case OperationADC: - if(decimal_flag_ && has_decimal_mode(personality)) { - const uint16_t decimalResult = uint16_t(a_) + uint16_t(operand_) + uint16_t(carry_flag_); + if(flags_.decimal && has_decimal_mode(personality)) { + const uint16_t decimalResult = uint16_t(a_) + uint16_t(operand_) + uint16_t(flags_.carry); - uint8_t low_nibble = (a_ & 0xf) + (operand_ & 0xf) + carry_flag_; + 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); - negative_result_ = uint8_t(result); - overflow_flag_ = (( (result^a_)&(result^operand_) )&0x80) >> 1; + flags_.negative_result = uint8_t(result); + flags_.overflow = (( (result^a_)&(result^operand_) )&0x80) >> 1; if(result >= 0xa0) result += 0x60; - carry_flag_ = (result >> 8) ? 1 : 0; + flags_.carry = (result >> 8) ? 1 : 0; a_ = uint8_t(result); - zero_result_ = uint8_t(decimalResult); + flags_.zero_result = uint8_t(decimalResult); if(is_65c02(personality)) { - negative_result_ = zero_result_ = a_; + flags_.set_nz(a_); read_mem(operand_, address_.full); break; } } else { - const uint16_t result = uint16_t(a_) + uint16_t(operand_) + uint16_t(carry_flag_); - overflow_flag_ = (( (result^a_)&(result^operand_) )&0x80) >> 1; - negative_result_ = zero_result_ = a_ = uint8_t(result); - carry_flag_ = (result >> 8)&1; + const uint16_t result = uint16_t(a_) + uint16_t(operand_) + uint16_t(flags_.carry); + flags_.overflow = (( (result^a_)&(result^operand_) )&0x80) >> 1; + flags_.set_nz(a_ = uint8_t(result)); + flags_.carry = (result >> 8)&1; } // fix up in case this was INS @@ -359,99 +359,99 @@ template void Proces // MARK: - Shifts and Rolls case OperationASL: - carry_flag_ = operand_ >> 7; + flags_.carry = operand_ >> 7; operand_ <<= 1; - negative_result_ = zero_result_ = operand_; + flags_.set_nz(operand_); continue; case OperationASO: - carry_flag_ = operand_ >> 7; + flags_.carry = operand_ >> 7; operand_ <<= 1; a_ |= operand_; - negative_result_ = zero_result_ = a_; + flags_.set_nz(a_); continue; case OperationROL: { - const uint8_t temp8 = uint8_t((operand_ << 1) | carry_flag_); - carry_flag_ = operand_ >> 7; - operand_ = negative_result_ = zero_result_ = temp8; + const uint8_t temp8 = uint8_t((operand_ << 1) | flags_.carry); + flags_.carry = operand_ >> 7; + flags_.set_nz(operand_ = temp8); } continue; case OperationRLA: { - const uint8_t temp8 = uint8_t((operand_ << 1) | carry_flag_); - carry_flag_ = operand_ >> 7; + const uint8_t temp8 = uint8_t((operand_ << 1) | flags_.carry); + flags_.carry = operand_ >> 7; operand_ = temp8; a_ &= operand_; - negative_result_ = zero_result_ = a_; + flags_.set_nz(a_); } continue; case OperationLSR: - carry_flag_ = operand_ & 1; + flags_.carry = operand_ & 1; operand_ >>= 1; - negative_result_ = zero_result_ = operand_; + flags_.set_nz(operand_); continue; case OperationLSE: - carry_flag_ = operand_ & 1; + flags_.carry = operand_ & 1; operand_ >>= 1; a_ ^= operand_; - negative_result_ = zero_result_ = a_; + flags_.set_nz(a_); continue; case OperationASR: a_ &= operand_; - carry_flag_ = a_ & 1; + flags_.carry = a_ & 1; a_ >>= 1; - negative_result_ = zero_result_ = a_; + flags_.set_nz(a_); continue; case OperationROR: { - const uint8_t temp8 = uint8_t((operand_ >> 1) | (carry_flag_ << 7)); - carry_flag_ = operand_ & 1; - operand_ = negative_result_ = zero_result_ = temp8; + const uint8_t temp8 = uint8_t((operand_ >> 1) | (flags_.carry << 7)); + flags_.carry = operand_ & 1; + flags_.set_nz(operand_ = temp8); } continue; case OperationRRA: { - const uint8_t temp8 = uint8_t((operand_ >> 1) | (carry_flag_ << 7)); - carry_flag_ = operand_ & 1; + const uint8_t temp8 = uint8_t((operand_ >> 1) | (flags_.carry << 7)); + flags_.carry = operand_ & 1; operand_ = temp8; } continue; case OperationDecrementOperand: operand_--; continue; case OperationIncrementOperand: operand_++; continue; - case OperationCLC: carry_flag_ = 0; continue; - case OperationCLI: inverse_interrupt_flag_ = Flag::Interrupt; continue; - case OperationCLV: overflow_flag_ = 0; continue; - case OperationCLD: decimal_flag_ = 0; continue; + case OperationCLC: flags_.carry = 0; continue; + case OperationCLI: flags_.inverse_interrupt = Flag::Interrupt; continue; + case OperationCLV: flags_.overflow = 0; continue; + case OperationCLD: flags_.decimal = 0; continue; - case OperationSEC: carry_flag_ = Flag::Carry; continue; - case OperationSEI: inverse_interrupt_flag_ = 0; continue; - case OperationSED: decimal_flag_ = Flag::Decimal; continue; + case OperationSEC: flags_.carry = Flag::Carry; continue; + case OperationSEI: flags_.inverse_interrupt = 0; continue; + case OperationSED: flags_.decimal = Flag::Decimal; continue; - case OperationINC: operand_++; negative_result_ = zero_result_ = operand_; continue; - case OperationDEC: operand_--; negative_result_ = zero_result_ = operand_; continue; - case OperationINA: a_++; negative_result_ = zero_result_ = a_; continue; - case OperationDEA: a_--; negative_result_ = zero_result_ = a_; continue; - case OperationINX: x_++; negative_result_ = zero_result_ = x_; continue; - case OperationDEX: x_--; negative_result_ = zero_result_ = x_; continue; - case OperationINY: y_++; negative_result_ = zero_result_ = y_; continue; - case OperationDEY: y_--; negative_result_ = zero_result_ = y_; continue; + case OperationINC: operand_++; flags_.set_nz(operand_); continue; + case OperationDEC: operand_--; flags_.set_nz(operand_); continue; + case OperationINA: a_++; flags_.set_nz(a_); continue; + case OperationDEA: a_--; flags_.set_nz(a_); continue; + case OperationINX: x_++; flags_.set_nz(x_); continue; + case OperationDEX: x_--; flags_.set_nz(x_); continue; + case OperationINY: y_++; flags_.set_nz(y_); continue; + case OperationDEY: y_--; flags_.set_nz(y_); continue; case OperationANE: a_ = (a_ | 0xee) & operand_ & x_; - negative_result_ = zero_result_ = a_; + flags_.set_nz(a_); continue; case OperationANC: a_ &= operand_; - negative_result_ = zero_result_ = a_; - carry_flag_ = a_ >> 7; + flags_.set_nz(a_); + flags_.carry = a_ >> 7; continue; case OperationLAS: a_ = x_ = s_ = s_ & operand_; - negative_result_ = zero_result_ = a_; + flags_.set_nz(a_); continue; // MARK: - Addressing Mode Work @@ -548,7 +548,7 @@ template void Proces throwaway_read(operand_); break; - case OperationIncrementPC: pc_.full++; continue; + case OperationIncrementPC: pc_.full++; continue; case CycleFetchOperandFromAddress: read_mem(operand_, address_.full); break; case CycleWriteOperandToAddress: write_mem(operand_, address_.full); break; @@ -560,14 +560,14 @@ template void Proces scheduled_program_counter_ = operations_[size_t(OperationsSlot::DoBRA)]; \ } - case OperationBPL: BRA(!(negative_result_&0x80)); continue; - case OperationBMI: BRA(negative_result_&0x80); continue; - case OperationBVC: BRA(!overflow_flag_); continue; - case OperationBVS: BRA(overflow_flag_); continue; - case OperationBCC: BRA(!carry_flag_); continue; - case OperationBCS: BRA(carry_flag_); continue; - case OperationBNE: BRA(zero_result_); continue; - case OperationBEQ: BRA(!zero_result_); continue; + case OperationBPL: BRA(!(flags_.negative_result&0x80)); continue; + case OperationBMI: BRA(flags_.negative_result&0x80); continue; + case OperationBVC: BRA(!flags_.overflow); continue; + case OperationBVS: BRA(flags_.overflow); continue; + case OperationBCC: BRA(!flags_.carry); continue; + case OperationBCS: BRA(flags_.carry); continue; + case OperationBNE: BRA(flags_.zero_result); continue; + case OperationBEQ: BRA(!flags_.zero_result); continue; case OperationBRA: BRA(true); continue; #undef BRA @@ -610,31 +610,31 @@ template void Proces // MARK: - Transfers - case OperationTXA: zero_result_ = negative_result_ = a_ = x_; continue; - case OperationTYA: zero_result_ = negative_result_ = a_ = y_; continue; - case OperationTXS: s_ = x_; continue; - case OperationTAY: zero_result_ = negative_result_ = y_ = a_; continue; - case OperationTAX: zero_result_ = negative_result_ = x_ = a_; continue; - case OperationTSX: zero_result_ = negative_result_ = x_ = s_; continue; + case OperationTXA: flags_.set_nz(a_ = x_); continue; + case OperationTYA: flags_.set_nz(a_ = y_); continue; + case OperationTXS: s_ = x_; continue; + case OperationTAY: flags_.set_nz(y_ = a_); continue; + case OperationTAX: flags_.set_nz(x_ = a_); continue; + case OperationTSX: flags_.set_nz(x_ = s_); continue; case OperationARR: - if(decimal_flag_) { + if(flags_.decimal) { a_ &= operand_; uint8_t unshiftedA = a_; - a_ = uint8_t((a_ >> 1) | (carry_flag_ << 7)); - zero_result_ = negative_result_ = a_; - overflow_flag_ = (a_^(a_ << 1))&Flag::Overflow; + a_ = uint8_t((a_ >> 1) | (flags_.carry << 7)); + flags_.set_nz(a_); + flags_.overflow = (a_^(a_ << 1))&Flag::Overflow; if((unshiftedA&0xf) + (unshiftedA&0x1) > 5) a_ = ((a_ + 6)&0xf) | (a_ & 0xf0); - carry_flag_ = ((unshiftedA&0xf0) + (unshiftedA&0x10) > 0x50) ? 1 : 0; - if(carry_flag_) a_ += 0x60; + flags_.carry = ((unshiftedA&0xf0) + (unshiftedA&0x10) > 0x50) ? 1 : 0; + if(flags_.carry) a_ += 0x60; } else { a_ &= operand_; - a_ = uint8_t((a_ >> 1) | (carry_flag_ << 7)); - negative_result_ = zero_result_ = a_; - carry_flag_ = (a_ >> 6)&1; - overflow_flag_ = (a_^(a_ << 1))&Flag::Overflow; + a_ = uint8_t((a_ >> 1) | (flags_.carry << 7)); + flags_.set_nz(a_); + flags_.carry = (a_ >> 6)&1; + flags_.overflow = (a_^(a_ << 1))&Flag::Overflow; } continue; @@ -642,8 +642,8 @@ template void Proces x_ &= a_; uint16_t difference = x_ - operand_; x_ = uint8_t(difference); - negative_result_ = zero_result_ = x_; - carry_flag_ = ((difference >> 8)&1)^1; + flags_.set_nz(x_); + flags_.carry = ((difference >> 8)&1)^1; continue; } @@ -691,13 +691,13 @@ void ProcessorBase::set_power_on(bool active) { } void ProcessorBase::set_irq_line(bool active) { - irq_line_ = active ? Flag::Interrupt : 0; + irq_line_ = active ? MOS6502Esque::Flag::Interrupt : 0; } void ProcessorBase::set_overflow_line(bool active) { // a leading edge will set the overflow flag if(active && !set_overflow_line_is_enabled_) - overflow_flag_ = Flag::Overflow; + flags_.overflow = MOS6502Esque::Flag::Overflow; set_overflow_line_is_enabled_ = active; } @@ -709,14 +709,9 @@ void ProcessorBase::set_nmi_line(bool active) { } uint8_t ProcessorStorage::get_flags() const { - return carry_flag_ | overflow_flag_ | (inverse_interrupt_flag_ ^ Flag::Interrupt) | (negative_result_ & 0x80) | (zero_result_ ? 0 : Flag::Zero) | Flag::Always | decimal_flag_; + return flags_.get(); } void ProcessorStorage::set_flags(uint8_t flags) { - carry_flag_ = flags & Flag::Carry; - negative_result_ = flags & Flag::Sign; - zero_result_ = (~flags) & Flag::Zero; - overflow_flag_ = flags & Flag::Overflow; - inverse_interrupt_flag_ = (~flags) & Flag::Interrupt; - decimal_flag_ = flags & Flag::Decimal; + flags_.set(flags); } diff --git a/Processors/6502/Implementation/6502Storage.cpp b/Processors/6502/Implementation/6502Storage.cpp index e87d6140a..8795e2e74 100644 --- a/Processors/6502/Implementation/6502Storage.cpp +++ b/Processors/6502/Implementation/6502Storage.cpp @@ -76,12 +76,6 @@ using namespace CPU::MOS6502; #define JAM {CycleFetchOperand, OperationScheduleJam} ProcessorStorage::ProcessorStorage(Personality personality) { - // only the interrupt flag is defined upon reset but get_flags isn't going to - // mask the other flags so we need to do that, at least - carry_flag_ &= Flag::Carry; - decimal_flag_ &= Flag::Decimal; - overflow_flag_ &= Flag::Overflow; - const InstructionList operations_6502[] = { /* 0x00 BRK */ Program(CycleIncPCPushPCH, CyclePushPCL, OperationBRKPickVector, OperationSetOperandFromFlagsWithBRKSet, CyclePushOperand, OperationSetIRQFlags, CycleReadVectorLow, CycleReadVectorHigh), /* 0x01 ORA x, ind */ IndexedIndirectRead(OperationORA), diff --git a/Processors/6502/Implementation/6502Storage.hpp b/Processors/6502/Implementation/6502Storage.hpp index a5ae557ee..d4dfecdf1 100644 --- a/Processors/6502/Implementation/6502Storage.hpp +++ b/Processors/6502/Implementation/6502Storage.hpp @@ -228,7 +228,7 @@ class ProcessorStorage { */ RegisterPair16 pc_, last_operation_pc_; uint8_t a_, x_, y_, s_ = 0; - uint8_t carry_flag_, negative_result_, zero_result_, decimal_flag_, overflow_flag_, inverse_interrupt_flag_ = 0; + MOS6502Esque::LazyFlags flags_; /* Temporary state for the micro programs. @@ -267,7 +267,7 @@ class ProcessorStorage { enum InterruptRequestFlags: uint8_t { Reset = 0x80, - IRQ = Flag::Interrupt, + IRQ = MOS6502Esque::Flag::Interrupt, NMI = 0x20, PowerOn = 0x10, diff --git a/Processors/6502Esque.hpp b/Processors/6502Esque/6502Esque.hpp similarity index 89% rename from Processors/6502Esque.hpp rename to Processors/6502Esque/6502Esque.hpp index c124b390d..38749b00e 100644 --- a/Processors/6502Esque.hpp +++ b/Processors/6502Esque/6502Esque.hpp @@ -9,6 +9,8 @@ #ifndef m6502Esque_h #define m6502Esque_h +#include "../../ClockReceiver/ClockReceiver.hpp" + /* This file defines how the CPU-controlled part of a bus looks for the 6502 and for other processors with a sufficiently-similar bus. @@ -35,6 +37,21 @@ enum Register { Y }; +/* + Flags as defined on the 6502; can be used to decode the result of @c get_value_of_register(Flags) or to form a value for + the corresponding set. +*/ +enum Flag: uint8_t { + Sign = 0x80, + Overflow = 0x40, + Always = 0x20, + Break = 0x10, + Decimal = 0x08, + Interrupt = 0x04, + Zero = 0x02, + Carry = 0x01 +}; + /*! Bus handlers will be given the task of performing bus operations, allowing them to provide whatever interface they like between a 6502 and the rest of the system. @c BusOperation lists the types of bus operation that may be requested. diff --git a/Processors/6502Selector.hpp b/Processors/6502Esque/6502Selector.hpp similarity index 96% rename from Processors/6502Selector.hpp rename to Processors/6502Esque/6502Selector.hpp index 6045d6a2e..411bba40f 100644 --- a/Processors/6502Selector.hpp +++ b/Processors/6502Esque/6502Selector.hpp @@ -9,8 +9,8 @@ #ifndef _502Selector_h #define _502Selector_h -#include "6502/6502.hpp" -#include "65816/65816.hpp" +#include "../6502/6502.hpp" +#include "../65816/65816.hpp" namespace CPU { namespace MOS6502Esque { diff --git a/Processors/6502Esque/Implementation/LazyFlags.hpp b/Processors/6502Esque/Implementation/LazyFlags.hpp new file mode 100644 index 000000000..5f091082c --- /dev/null +++ b/Processors/6502Esque/Implementation/LazyFlags.hpp @@ -0,0 +1,66 @@ +// +// LazyFlags.hpp +// Clock Signal +// +// Created by Thomas Harte on 05/10/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#ifndef LazyFlags_h +#define LazyFlags_h + +#include "../6502Esque.hpp" + +namespace CPU { +namespace MOS6502Esque { + +struct LazyFlags { + /// Bit 7 is set if the negative flag is set; otherwise it is clear. + uint8_t negative_result; + + /// Non-zero if the zero flag is clear, zero if it is set. + uint8_t zero_result; + + /// Contains Flag::Carry. + uint8_t carry; + + /// Contains Flag::Decimal. + uint8_t decimal; + + /// Contains Flag::Overflow. + uint8_t overflow; + + /// Contains Flag::Interrupt, complemented. + uint8_t inverse_interrupt = 0; + + void set_nz(uint8_t value) { + zero_result = negative_result = value; + } + + void set(uint8_t flags) { + carry = flags & Flag::Carry; + negative_result = flags & Flag::Sign; + zero_result = (~flags) & Flag::Zero; + overflow = flags & Flag::Overflow; + inverse_interrupt = (~flags) & Flag::Interrupt; + decimal = flags & Flag::Decimal; + } + + uint8_t get() const { + return carry | overflow | (inverse_interrupt ^ Flag::Interrupt) | (negative_result & 0x80) | (zero_result ? 0 : Flag::Zero) | Flag::Always | decimal; + } + + LazyFlags() { + // Only the interrupt flag is defined upon reset but get_flags isn't going to + // mask the other flags so we need to do that, at least. + carry &= Flag::Carry; + decimal &= Flag::Decimal; + overflow &= Flag::Overflow; + } +}; + + +} +} + +#endif /* LazyFlags_h */ diff --git a/Processors/6502Esque/README.md b/Processors/6502Esque/README.md new file mode 100644 index 000000000..e2e0ddee4 --- /dev/null +++ b/Processors/6502Esque/README.md @@ -0,0 +1,3 @@ +# 6502Esque + +This folder contains common code for CPUs for a 6502-esque bus interface; it also contains a special template, the 6502Selector, which allows a consumer to select between the 6502-esque chips by enum. diff --git a/Processors/65816/65816.hpp b/Processors/65816/65816.hpp index a08fd59c6..0d73c0a04 100644 --- a/Processors/65816/65816.hpp +++ b/Processors/65816/65816.hpp @@ -16,7 +16,7 @@ #include "../RegisterSizes.hpp" #include "../../ClockReceiver/ClockReceiver.hpp" -#include "../6502Esque.hpp" +#include "../6502Esque/6502Esque.hpp" namespace CPU { namespace WDC65816 { diff --git a/Processors/65816/Implementation/65816Implementation.hpp b/Processors/65816/Implementation/65816Implementation.hpp index 50844b09c..79e0037bf 100644 --- a/Processors/65816/Implementation/65816Implementation.hpp +++ b/Processors/65816/Implementation/65816Implementation.hpp @@ -372,8 +372,10 @@ template void Processor::run_for(const Cycles } break; -// default: -// assert(false); + // TODO: OperationCopyPBRToData, OperationPrepareException + + default: + assert(false); } number_of_cycles -= bus_handler_.perform_bus_operation(bus_operation, bus_address, bus_value);