diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 212170c54..f1f0c2126 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -783,6 +783,8 @@ 4BC131772346DE9100E4FF3D /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC131752346DE9100E4FF3D /* StaticAnalyser.cpp */; }; 4BC1317A2346DF2B00E4FF3D /* MSA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC131782346DF2B00E4FF3D /* MSA.cpp */; }; 4BC1317B2346DF2B00E4FF3D /* MSA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC131782346DF2B00E4FF3D /* MSA.cpp */; }; + 4BC57CD92436A62900FBC404 /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC57CD82436A62900FBC404 /* State.cpp */; }; + 4BC57CDA2436A62900FBC404 /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC57CD82436A62900FBC404 /* State.cpp */; }; 4BC5C3E022C994CD00795658 /* 68000MoveTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BC5C3DF22C994CC00795658 /* 68000MoveTests.mm */; }; 4BC5FC3020CDDDEF00410AA0 /* AppleIIOptions.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BC5FC2E20CDDDEE00410AA0 /* AppleIIOptions.xib */; }; 4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC751B11D157E61006C31D9 /* 6522Tests.swift */; }; @@ -1655,6 +1657,8 @@ 4BC57CD2243427C700FBC404 /* AudioProducer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AudioProducer.hpp; sourceTree = ""; }; 4BC57CD32434282000FBC404 /* TimedMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TimedMachine.hpp; sourceTree = ""; }; 4BC57CD424342E0600FBC404 /* MachineTypes.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MachineTypes.hpp; sourceTree = ""; }; + 4BC57CD72436A61300FBC404 /* State.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = State.hpp; sourceTree = ""; }; + 4BC57CD82436A62900FBC404 /* State.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = State.cpp; sourceTree = ""; }; 4BC5C3DF22C994CC00795658 /* 68000MoveTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000MoveTests.mm; sourceTree = ""; }; 4BC5FC2F20CDDDEE00410AA0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/AppleIIOptions.xib"; sourceTree = SOURCE_ROOT; }; 4BC751B11D157E61006C31D9 /* 6522Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6522Tests.swift; sourceTree = ""; }; @@ -1939,6 +1943,7 @@ 4B6A4C8E1F58F09E00E3F787 /* 6502.hpp */, 4B6A4C901F58F09E00E3F787 /* AllRAM */, 4B6A4C931F58F09E00E3F787 /* Implementation */, + 4BC57CD62436A61300FBC404 /* State */, ); path = 6502; sourceTree = ""; @@ -3504,6 +3509,15 @@ path = AtariST; sourceTree = ""; }; + 4BC57CD62436A61300FBC404 /* State */ = { + isa = PBXGroup; + children = ( + 4BC57CD72436A61300FBC404 /* State.hpp */, + 4BC57CD82436A62900FBC404 /* State.cpp */, + ); + path = State; + sourceTree = ""; + }; 4BC9DF4A1D04691600F44158 /* Components */ = { isa = PBXGroup; children = ( @@ -4289,6 +4303,7 @@ 4B055AAA1FAE85F50060FFFF /* CPM.cpp in Sources */, 4B055A9A1FAE85CB0060FFFF /* MFMDiskController.cpp in Sources */, 4B0ACC3123775819008902D0 /* TIASound.cpp in Sources */, + 4BC57CDA2436A62900FBC404 /* State.cpp in Sources */, 4B055ACB1FAE9AFB0060FFFF /* SerialBus.cpp in Sources */, 4B8318B122D3E53A006DB630 /* DiskIICard.cpp in Sources */, 4B055A9B1FAE85DA0060FFFF /* AcornADF.cpp in Sources */, @@ -4552,6 +4567,7 @@ 4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */, 4B2B3A4C1F9B8FA70062DABF /* MemoryFuzzer.cpp in Sources */, 4B7913CC1DFCD80E00175A82 /* Video.cpp in Sources */, + 4BC57CD92436A62900FBC404 /* State.cpp in Sources */, 4BDA00E622E699B000AC3CD0 /* CSMachine.mm in Sources */, 4B4518831F75E91A00926311 /* PCMTrack.cpp in Sources */, 4B0ACC3223775819008902D0 /* Atari2600.cpp in Sources */, diff --git a/OSBindings/SDL/SConstruct b/OSBindings/SDL/SConstruct index 3889c723d..8f2414371 100644 --- a/OSBindings/SDL/SConstruct +++ b/OSBindings/SDL/SConstruct @@ -82,6 +82,7 @@ SOURCES += glob.glob('../../Outputs/OpenGL/*.cpp') SOURCES += glob.glob('../../Outputs/OpenGL/Primitives/*.cpp') SOURCES += glob.glob('../../Processors/6502/Implementation/*.cpp') +SOURCES += glob.glob('../../Processors/6502/State/*.cpp') SOURCES += glob.glob('../../Processors/68000/Implementation/*.cpp') SOURCES += glob.glob('../../Processors/Z80/Implementation/*.cpp') diff --git a/Processors/6502/6502.hpp b/Processors/6502/6502.hpp index 77192a93d..74a69da76 100644 --- a/Processors/6502/6502.hpp +++ b/Processors/6502/6502.hpp @@ -15,8 +15,6 @@ #include "../RegisterSizes.hpp" #include "../../ClockReceiver/ClockReceiver.hpp" -#include "../../Reflection/Enum.hpp" -#include "../../Reflection/Struct.hpp" namespace CPU { namespace MOS6502 { @@ -129,81 +127,6 @@ class ProcessorBase: public ProcessorStorage { public: ProcessorBase(Personality personality) : ProcessorStorage(personality) {} - struct State: public Reflection::StructImpl { - /*! - Provides the current state of the well-known, published internal registers. - */ - struct Registers: public Reflection::StructImpl { - uint16_t program_counter; - uint8_t stack_pointer; - uint8_t flags; - uint8_t a, x, y; - - Registers(); - } registers; - - /*! - Provides the current state of the processor's various input lines that aren't - related to an access cycle. - */ - struct Inputs: public Reflection::StructImpl { - bool ready; - bool irq; - bool nmi; - bool reset; - - Inputs(); - } inputs; - - /*! - Contains internal state used by this particular implementation of a 6502. Most of it - does not necessarily correlate with anything in a real 6502, and some of it very - obviously doesn't. - */ - struct ExecutionState: public Reflection::StructImpl { - ReflectableEnum(Phase, - Instruction, Stopped, Waiting, Jammed, Ready - ); - - /// Current executon phase, e.g. standard instruction flow or responding to an IRQ. - Phase phase; - int micro_program; - int micro_program_offset; - - // The following are very internal things. At the minute I - // consider these 'reliable' for inter-launch state - // preservation only on the grounds that this implementation - // of a 6502 is now empirically stable. - // - // If cycles_into_phase is 0, the values below need not be - // retained, they're entirely ephemeral. If providing a state - // for persistance, machines that can should advance until - // cycles_into_phase is 0. - uint8_t operation, operand; - uint16_t address, next_address; - - ExecutionState(); - } execution_state; - - State() { - if(needs_declare()) { - DeclareField(registers); - DeclareField(execution_state); - DeclareField(inputs); - } - } - }; - - /*! - Gets current processor state. - */ - State get_state(); - - /*! - Sets current processor state. - */ - void set_state(const State &); - /*! Gets the value of a register. @@ -212,7 +135,7 @@ class ProcessorBase: public ProcessorStorage { @param r The register to set. @returns The value of the register. 8-bit registers will be returned as unsigned. */ - uint16_t get_value_of_register(Register r); + uint16_t get_value_of_register(Register r) const; /*! Sets the value of a register. @@ -236,7 +159,7 @@ class ProcessorBase: public ProcessorStorage { @returns @c true if the line is logically active; @c false otherwise. */ - inline bool get_is_resetting(); + inline bool get_is_resetting() const; /*! This emulation automatically sets itself up in power-on state at creation, which has the effect of triggering a @@ -271,43 +194,9 @@ class ProcessorBase: public ProcessorStorage { @returns @c true if the 6502 is jammed; @c false otherwise. */ - bool is_jammed(); + bool is_jammed() const; }; -// Boilerplate follows here, to establish 'reflection' for the state struct defined above. -inline ProcessorBase::State::Registers::Registers() { - if(needs_declare()) { - DeclareField(program_counter); - DeclareField(stack_pointer); - DeclareField(flags); - DeclareField(a); - DeclareField(x); - DeclareField(y); - } -} - -inline ProcessorBase::State::ExecutionState::ExecutionState() { - if(needs_declare()) { - AnnounceEnum(Phase); - DeclareField(phase); - DeclareField(micro_program); - DeclareField(micro_program_offset); - DeclareField(operation); - DeclareField(operand); - DeclareField(address); - DeclareField(next_address); - } -} - -inline ProcessorBase::State::Inputs::Inputs() { - if(needs_declare()) { - DeclareField(ready); - DeclareField(irq); - DeclareField(nmi); - DeclareField(reset); - } -} - /*! @abstact Template providing emulation of a 6502 processor. diff --git a/Processors/6502/Implementation/6502Base.cpp b/Processors/6502/Implementation/6502Base.cpp index f82294b72..8c629327b 100644 --- a/Processors/6502/Implementation/6502Base.cpp +++ b/Processors/6502/Implementation/6502Base.cpp @@ -14,7 +14,7 @@ using namespace CPU::MOS6502; const uint8_t CPU::MOS6502::JamOpcode = 0xf2; -uint16_t ProcessorBase::get_value_of_register(Register r) { +uint16_t ProcessorBase::get_value_of_register(Register r) const { switch (r) { case Register::ProgramCounter: return pc_.full; case Register::LastOperationAddress: return last_operation_pc_.full; @@ -39,82 +39,6 @@ void ProcessorBase::set_value_of_register(Register r, uint16_t value) { } } -bool ProcessorBase::is_jammed() { +bool ProcessorBase::is_jammed() const { return is_jammed_; } - -ProcessorBase::State ProcessorBase::get_state() { - ProcessorBase::State state; - - // Fill in registers. - state.registers.program_counter = pc_.full; - state.registers.stack_pointer = s_; - state.registers.flags = get_flags(); - state.registers.a = a_; - state.registers.x = x_; - state.registers.y = y_; - - // Fill in other inputs. - state.inputs.ready = ready_line_is_enabled_; - state.inputs.irq = irq_line_; - state.inputs.nmi = nmi_line_is_enabled_; - state.inputs.reset = interrupt_requests_ & (InterruptRequestFlags::Reset | InterruptRequestFlags::PowerOn); - - // Fill in execution state. - state.execution_state.operation = operation_; - state.execution_state.operand = operand_; - state.execution_state.address = address_.full; - state.execution_state.next_address = next_address_.full; - if(ready_is_active_) { - state.execution_state.phase = State::ExecutionState::Phase::Ready; - } else if(is_jammed_) { - state.execution_state.phase = State::ExecutionState::Phase::Jammed; - } else if(wait_is_active_) { - state.execution_state.phase = State::ExecutionState::Phase::Waiting; - } else if(stop_is_active_) { - state.execution_state.phase = State::ExecutionState::Phase::Stopped; - } else { - state.execution_state.phase = State::ExecutionState::Phase::Instruction; - } - - const auto micro_offset = size_t(scheduled_program_counter_ - &operations_[0][0]); - const auto list_length = sizeof(InstructionList) / sizeof(MicroOp); - - state.execution_state.micro_program = int(micro_offset / list_length); - state.execution_state.micro_program_offset = int(micro_offset % list_length); - assert(&operations_[state.execution_state.micro_program][state.execution_state.micro_program_offset] == scheduled_program_counter_); - - return state; -} - -void ProcessorBase::set_state(const State &state) { - // Grab registers. - pc_.full = state.registers.program_counter; - s_ = state.registers.stack_pointer; - set_flags(state.registers.flags); - a_ = state.registers.a; - x_ = state.registers.x; - y_ = state.registers.y; - - // Grab other inputs. - ready_line_is_enabled_ = state.inputs.ready; - set_irq_line(state.inputs.irq); - set_nmi_line(state.inputs.nmi); - set_reset_line(state.inputs.reset); - - // Set execution state. - ready_is_active_ = is_jammed_ = wait_is_active_ = stop_is_active_ = false; - switch(state.execution_state.phase) { - case State::ExecutionState::Phase::Ready: ready_is_active_ = true; break; - case State::ExecutionState::Phase::Jammed: is_jammed_ = true; break; - case State::ExecutionState::Phase::Stopped: stop_is_active_ = true; break; - case State::ExecutionState::Phase::Waiting: wait_is_active_ = true; break; - case State::ExecutionState::Phase::Instruction: break; - } - - operation_ = state.execution_state.operation; - operand_ = state.execution_state.operand; - address_.full = state.execution_state.address; - next_address_.full = state.execution_state.next_address; - scheduled_program_counter_ = &operations_[state.execution_state.micro_program][state.execution_state.micro_program_offset]; -} diff --git a/Processors/6502/Implementation/6502Implementation.hpp b/Processors/6502/Implementation/6502Implementation.hpp index 03706c04f..35c2af3e0 100644 --- a/Processors/6502/Implementation/6502Implementation.hpp +++ b/Processors/6502/Implementation/6502Implementation.hpp @@ -38,14 +38,12 @@ template void Proces } else {\ scheduled_program_counter_ = operations_[size_t(OperationsSlot::FetchDecodeExecute)];\ }\ - cycles_in_phase_ = 0; \ } #define bus_access() \ interrupt_requests_ = (interrupt_requests_ & ~InterruptRequestFlags::IRQ) | irq_request_history_; \ irq_request_history_ = irq_line_ & inverse_interrupt_flag_; \ number_of_cycles -= bus_handler_.perform_bus_operation(nextBusOperation, busAddress, busValue); \ - ++cycles_in_phase_; \ nextBusOperation = BusOperation::None; \ if(number_of_cycles <= Cycles(0)) break; @@ -57,13 +55,11 @@ template void Proces // Deal with a potential RDY state, if this 6502 has anything connected to ready. while(uses_ready_line && ready_is_active_ && number_of_cycles > Cycles(0)) { number_of_cycles -= bus_handler_.perform_bus_operation(BusOperation::Ready, busAddress, busValue); - ++cycles_in_phase_; } // Deal with a potential STP state, if this 6502 implements STP. while(has_stpwai(personality) && stop_is_active_ && number_of_cycles > Cycles(0)) { number_of_cycles -= bus_handler_.perform_bus_operation(BusOperation::Ready, busAddress, busValue); - ++cycles_in_phase_; if(interrupt_requests_ & InterruptRequestFlags::Reset) { stop_is_active_ = false; checkSchedule(); @@ -74,7 +70,6 @@ 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); - ++cycles_in_phase_; interrupt_requests_ |= (irq_line_ & inverse_interrupt_flag_); if(interrupt_requests_ & InterruptRequestFlags::NMI || irq_line_) { wait_is_active_ = false; @@ -685,7 +680,7 @@ void ProcessorBase::set_reset_line(bool active) { interrupt_requests_ = (interrupt_requests_ & ~InterruptRequestFlags::Reset) | (active ? InterruptRequestFlags::Reset : 0); } -bool ProcessorBase::get_is_resetting() { +bool ProcessorBase::get_is_resetting() const { return interrupt_requests_ & (InterruptRequestFlags::Reset | InterruptRequestFlags::PowerOn); } @@ -711,7 +706,7 @@ void ProcessorBase::set_nmi_line(bool active) { nmi_line_is_enabled_ = active; } -uint8_t ProcessorStorage::get_flags() { +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_; } diff --git a/Processors/6502/Implementation/6502Storage.hpp b/Processors/6502/Implementation/6502Storage.hpp index 89801bd4f..c9001ab4f 100644 --- a/Processors/6502/Implementation/6502Storage.hpp +++ b/Processors/6502/Implementation/6502Storage.hpp @@ -225,7 +225,6 @@ class ProcessorStorage { InstructionList operations_[size_t(OperationsSlot::Max)]; const MicroOp *scheduled_program_counter_ = nullptr; - int cycles_in_phase_ = 0; /* Storage for the 6502 registers; F is stored as individual flags. @@ -255,7 +254,7 @@ class ProcessorStorage { @returns The current value of the flags register. */ - inline uint8_t get_flags(); + inline uint8_t get_flags() const; /*! Sets the flags register. @@ -285,6 +284,9 @@ class ProcessorStorage { uint8_t irq_line_ = 0, irq_request_history_ = 0; bool nmi_line_is_enabled_ = false, set_overflow_line_is_enabled_ = false; + + // Allow state objects to capture and install state. + friend class State; }; #endif /* _502Storage_h */ diff --git a/Processors/6502/State/State.cpp b/Processors/6502/State/State.cpp new file mode 100644 index 000000000..e71d610ae --- /dev/null +++ b/Processors/6502/State/State.cpp @@ -0,0 +1,125 @@ +// +// State.cpp +// Clock Signal +// +// Created by Thomas Harte on 02/04/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#include "State.hpp" + +using namespace CPU::MOS6502; + +State::State(const ProcessorBase &src): State() { + // Fill in registers. + registers.program_counter = src.pc_.full; + registers.stack_pointer = src.s_; + registers.flags = src.get_flags(); + registers.a = src.a_; + registers.x = src.x_; + registers.y = src.y_; + + // Fill in other inputs. + inputs.ready = src.ready_line_is_enabled_; + inputs.irq = src.irq_line_; + inputs.nmi = src.nmi_line_is_enabled_; + inputs.reset = src.interrupt_requests_ & (ProcessorStorage::InterruptRequestFlags::Reset | ProcessorStorage::InterruptRequestFlags::PowerOn); + + // Fill in execution state. + execution_state.operation = src.operation_; + execution_state.operand = src.operand_; + execution_state.address = src.address_.full; + execution_state.next_address = src.next_address_.full; + if(src.ready_is_active_) { + execution_state.phase = State::ExecutionState::Phase::Ready; + } else if(src.is_jammed_) { + execution_state.phase = State::ExecutionState::Phase::Jammed; + } else if(src.wait_is_active_) { + execution_state.phase = State::ExecutionState::Phase::Waiting; + } else if(src.stop_is_active_) { + execution_state.phase = State::ExecutionState::Phase::Stopped; + } else { + execution_state.phase = State::ExecutionState::Phase::Instruction; + } + + const auto micro_offset = size_t(src.scheduled_program_counter_ - &src.operations_[0][0]); + const auto list_length = sizeof(ProcessorStorage::InstructionList) / sizeof(ProcessorStorage::MicroOp); + + execution_state.micro_program = int(micro_offset / list_length); + execution_state.micro_program_offset = int(micro_offset % list_length); + assert(&src.operations_[execution_state.micro_program][execution_state.micro_program_offset] == src.scheduled_program_counter_); +} + +void State::apply(ProcessorBase &target) { + // Grab registers. + target.pc_.full = registers.program_counter; + target.s_ = registers.stack_pointer; + target.set_flags(registers.flags); + target.a_ = registers.a; + target.x_ = registers.x; + target.y_ = registers.y; + + // Grab other inputs. + target.ready_line_is_enabled_ = inputs.ready; + target.set_irq_line(inputs.irq); + target.set_nmi_line(inputs.nmi); + target.set_reset_line(inputs.reset); + + // Set execution state. + target.ready_is_active_ = target.is_jammed_ = target.wait_is_active_ = target.stop_is_active_ = false; + switch(execution_state.phase) { + case State::ExecutionState::Phase::Ready: target.ready_is_active_ = true; break; + case State::ExecutionState::Phase::Jammed: target.is_jammed_ = true; break; + case State::ExecutionState::Phase::Stopped: target.stop_is_active_ = true; break; + case State::ExecutionState::Phase::Waiting: target.wait_is_active_ = true; break; + case State::ExecutionState::Phase::Instruction: break; + } + + target.operation_ = execution_state.operation; + target.operand_ = execution_state.operand; + target.address_.full = execution_state.address; + target.next_address_.full = execution_state.next_address; + target.scheduled_program_counter_ = &target.operations_[execution_state.micro_program][execution_state.micro_program_offset]; +} + +// Boilerplate follows here, to establish 'reflection'. +State::State() { + if(needs_declare()) { + DeclareField(registers); + DeclareField(execution_state); + DeclareField(inputs); + } +} + +State::Registers::Registers() { + if(needs_declare()) { + DeclareField(program_counter); + DeclareField(stack_pointer); + DeclareField(flags); + DeclareField(a); + DeclareField(x); + DeclareField(y); + } +} + +State::ExecutionState::ExecutionState() { + if(needs_declare()) { + AnnounceEnum(Phase); + DeclareField(phase); + DeclareField(micro_program); + DeclareField(micro_program_offset); + DeclareField(operation); + DeclareField(operand); + DeclareField(address); + DeclareField(next_address); + } +} + +State::Inputs::Inputs() { + if(needs_declare()) { + DeclareField(ready); + DeclareField(irq); + DeclareField(nmi); + DeclareField(reset); + } +} diff --git a/Processors/6502/State/State.hpp b/Processors/6502/State/State.hpp new file mode 100644 index 000000000..34246c11d --- /dev/null +++ b/Processors/6502/State/State.hpp @@ -0,0 +1,96 @@ +// +// State.h +// Clock Signal +// +// Created by Thomas Harte on 02/04/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#ifndef State_h +#define State_h + +#include "../../../Reflection/Enum.hpp" +#include "../../../Reflection/Struct.hpp" +#include "../6502.hpp" + +namespace CPU { +namespace MOS6502 { + +/*! + Provides a means for capturing or restoring complete 6502 state. + + This is an optional adjunct to the 6502 class. If you want to take the rest of the 6502 + implementation but don't want any of the overhead of my sort-of half-reflection as + encapsulated in Reflection/[Enum/Struct].hpp just don't use this class. +*/ +struct State: public Reflection::StructImpl { + /*! + Provides the current state of the well-known, published internal registers. + */ + struct Registers: public Reflection::StructImpl { + uint16_t program_counter; + uint8_t stack_pointer; + uint8_t flags; + uint8_t a, x, y; + + Registers(); + } registers; + + /*! + Provides the current state of the processor's various input lines that aren't + related to an access cycle. + */ + struct Inputs: public Reflection::StructImpl { + bool ready; + bool irq; + bool nmi; + bool reset; + + Inputs(); + } inputs; + + /*! + Contains internal state used by this particular implementation of a 6502. Most of it + does not necessarily correlate with anything in a real 6502, and some of it very + obviously doesn't. + */ + struct ExecutionState: public Reflection::StructImpl { + ReflectableEnum(Phase, + Instruction, Stopped, Waiting, Jammed, Ready + ); + + /// Current executon phase, e.g. standard instruction flow or responding to an IRQ. + Phase phase; + int micro_program; + int micro_program_offset; + + // The following are very internal things. At the minute I + // consider these 'reliable' for inter-launch state + // preservation only on the grounds that this implementation + // of a 6502 is now empirically stable. + // + // If cycles_into_phase is 0, the values below need not be + // retained, they're entirely ephemeral. If providing a state + // for persistance, machines that can should advance until + // cycles_into_phase is 0. + uint8_t operation, operand; + uint16_t address, next_address; + + ExecutionState(); + } execution_state; + + /// Default constructor; makes no guarantees as to field values beyond those given above. + State(); + + /// Instantiates a new State based on the processor @c src. + State(const ProcessorBase &src); + + /// Applies this state to @c target. + void apply(ProcessorBase &target); +}; + + +} +} + +#endif /* State_h */