diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index c25db431d..b8b1f8688 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -141,6 +141,8 @@ 4B15A9FD208249BB005E6C8D /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B15A9FA208249BB005E6C8D /* StaticAnalyser.cpp */; }; 4B17B58B20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B17B58920A8A9D9007CCA8F /* StringSerialiser.cpp */; }; 4B17B58C20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B17B58920A8A9D9007CCA8F /* StringSerialiser.cpp */; }; + 4B1B58F6246CC4E8009C171E /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1B58F4246CC4E8009C171E /* State.cpp */; }; + 4B1B58F7246CC4E8009C171E /* State.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1B58F4246CC4E8009C171E /* State.cpp */; }; 4B1B88BB202E2EC100B67DFF /* MultiKeyboardMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1B88B9202E2EC100B67DFF /* MultiKeyboardMachine.cpp */; }; 4B1B88BC202E2EC100B67DFF /* MultiKeyboardMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1B88B9202E2EC100B67DFF /* MultiKeyboardMachine.cpp */; }; 4B1B88BD202E3D3D00B67DFF /* MultiMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FCC3F201EC24200960631 /* MultiMachine.cpp */; }; @@ -984,6 +986,8 @@ 4B1667FB1FFF215F00A16032 /* KonamiWithSCC.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = KonamiWithSCC.hpp; path = MSX/Cartridges/KonamiWithSCC.hpp; sourceTree = ""; }; 4B17B58920A8A9D9007CCA8F /* StringSerialiser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StringSerialiser.cpp; sourceTree = ""; }; 4B17B58A20A8A9D9007CCA8F /* StringSerialiser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StringSerialiser.hpp; sourceTree = ""; }; + 4B1B58F4246CC4E8009C171E /* State.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = State.cpp; sourceTree = ""; }; + 4B1B58F5246CC4E8009C171E /* State.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = State.hpp; sourceTree = ""; }; 4B1B88B9202E2EC100B67DFF /* MultiKeyboardMachine.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiKeyboardMachine.cpp; sourceTree = ""; }; 4B1B88BA202E2EC100B67DFF /* MultiKeyboardMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiKeyboardMachine.hpp; sourceTree = ""; }; 4B1B88BE202E3DB200B67DFF /* MultiConfigurable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiConfigurable.cpp; sourceTree = ""; }; @@ -2008,6 +2012,16 @@ name = Cartridges; sourceTree = ""; }; + 4B1B58F3246CC4E8009C171E /* State */ = { + isa = PBXGroup; + children = ( + 4B1B58F4246CC4E8009C171E /* State.cpp */, + 4B1B58F5246CC4E8009C171E /* State.hpp */, + ); + name = State; + path = Z80/State; + sourceTree = ""; + }; 4B1E85791D174DEC001EF87D /* 6532 */ = { isa = PBXGroup; children = ( @@ -2630,6 +2644,7 @@ 4B77069C1EC904570053B588 /* Z80.hpp */, 4B322DFC1F5A2981004EB04C /* AllRAM */, 4B322DFF1F5A2981004EB04C /* Implementation */, + 4B1B58F3246CC4E8009C171E /* State */, ); name = Z80; sourceTree = ""; @@ -4441,6 +4456,7 @@ 4B055ACC1FAE9B030060FFFF /* Electron.cpp in Sources */, 4B74CF822312FA9C00500CE8 /* HFV.cpp in Sources */, 4B8318B022D3E531006DB630 /* AppleII.cpp in Sources */, + 4B1B58F7246CC4E8009C171E /* State.cpp in Sources */, 4B0ACC03237756F6008902D0 /* Line.cpp in Sources */, 4B055AB11FAE86070060FFFF /* Tape.cpp in Sources */, 4BC1317B2346DF2B00E4FF3D /* MSA.cpp in Sources */, @@ -4555,6 +4571,7 @@ 4B9BE400203A0C0600FFAE60 /* MultiSpeaker.cpp in Sources */, 4B894538201967B4007DE474 /* Tape.cpp in Sources */, 4B54C0CB1F8D92590050900F /* Keyboard.cpp in Sources */, + 4B1B58F6246CC4E8009C171E /* State.cpp in Sources */, 4BEA525E1DF33323007E74F2 /* Tape.cpp in Sources */, 4B2BF19623E10F0100C3AD60 /* CSHighPrecisionTimer.m in Sources */, 4B8334951F5E25B60097E338 /* C1540.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/OSBindings/Mac/Clock Signal.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 87fffc12d..919434a62 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/Processors/6502/Implementation/6502Storage.hpp b/Processors/6502/Implementation/6502Storage.hpp index c9001ab4f..e5464430c 100644 --- a/Processors/6502/Implementation/6502Storage.hpp +++ b/Processors/6502/Implementation/6502Storage.hpp @@ -285,7 +285,7 @@ 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. + // Allow state objects to capture and apply state. friend class State; }; diff --git a/Processors/6502/State/State.cpp b/Processors/6502/State/State.cpp index e71d610ae..def2e6fdc 100644 --- a/Processors/6502/State/State.cpp +++ b/Processors/6502/State/State.cpp @@ -11,7 +11,7 @@ using namespace CPU::MOS6502; State::State(const ProcessorBase &src): State() { - // Fill in registers. + // Registers. registers.program_counter = src.pc_.full; registers.stack_pointer = src.s_; registers.flags = src.get_flags(); @@ -19,13 +19,13 @@ State::State(const ProcessorBase &src): State() { registers.x = src.x_; registers.y = src.y_; - // Fill in other inputs. + // 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. execution_state.operation = src.operation_; execution_state.operand = src.operand_; execution_state.address = src.address_.full; @@ -51,7 +51,7 @@ State::State(const ProcessorBase &src): State() { } void State::apply(ProcessorBase &target) { - // Grab registers. + // Registers. target.pc_.full = registers.program_counter; target.s_ = registers.stack_pointer; target.set_flags(registers.flags); @@ -59,13 +59,13 @@ void State::apply(ProcessorBase &target) { target.x_ = registers.x; target.y_ = registers.y; - // Grab other inputs. + // 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. + // 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; diff --git a/Processors/6502/State/State.hpp b/Processors/6502/State/State.hpp index 34246c11d..c641c7fa6 100644 --- a/Processors/6502/State/State.hpp +++ b/Processors/6502/State/State.hpp @@ -1,13 +1,13 @@ // -// State.h +// State.hpp // Clock Signal // // Created by Thomas Harte on 02/04/2020. // Copyright © 2020 Thomas Harte. All rights reserved. // -#ifndef State_h -#define State_h +#ifndef State_hpp +#define State_hpp #include "../../../Reflection/Enum.hpp" #include "../../../Reflection/Struct.hpp" @@ -93,4 +93,4 @@ struct State: public Reflection::StructImpl { } } -#endif /* State_h */ +#endif /* State_hpp */ diff --git a/Processors/Z80/Implementation/Z80Storage.hpp b/Processors/Z80/Implementation/Z80Storage.hpp index 1008a2819..3269210ad 100644 --- a/Processors/Z80/Implementation/Z80Storage.hpp +++ b/Processors/Z80/Implementation/Z80Storage.hpp @@ -195,8 +195,8 @@ class ProcessorStorage { @returns The current value of the flags register. */ - uint8_t get_flags() { - uint8_t result = + uint8_t get_flags() const { + return (sign_result_ & Flag::Sign) | (zero_result_ ? 0 : Flag::Zero) | (bit53_result_ & (Flag::Bit5 | Flag::Bit3)) | @@ -204,7 +204,6 @@ class ProcessorStorage { (parity_overflow_result_ & Flag::Parity) | subtract_flag_ | (carry_result_ & Flag::Carry); - return result; } /*! @@ -232,4 +231,6 @@ class ProcessorStorage { void assemble_cb_page(InstructionPage &target, RegisterPair16 &index, bool add_offsets); void assemble_base_page(InstructionPage &target, RegisterPair16 &index, bool add_offsets, InstructionPage &cb_page); + // Allos state objects to capture and apply state. + friend class State; }; diff --git a/Processors/Z80/State/State.cpp b/Processors/Z80/State/State.cpp new file mode 100644 index 000000000..5e38dea47 --- /dev/null +++ b/Processors/Z80/State/State.cpp @@ -0,0 +1,110 @@ +// +// State.cpp +// Clock Signal +// +// Created by Thomas Harte on 13/05/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#include "State.hpp" + +using namespace CPU::Z80; + +State::State(const ProcessorBase &src): State() { + // Registers. + registers.a = src.a_; + registers.flags = src.get_flags(); + registers.bc = src.bc_.full; + registers.de = src.de_.full; + registers.hl = src.hl_.full; + registers.bcDash = src.bcDash_.full; + registers.deDash = src.deDash_.full; + registers.hlDash = src.hlDash_.full; + registers.ix = src.ix_.full; + registers.iy = src.iy_.full; + registers.ir = src.ir_.full; + registers.program_counter = src.pc_.full; + registers.stack_pointer = src.sp_.full; + registers.memptr = src.memptr_.full; + registers.interrupt_mode = src.interrupt_mode_; + registers.iff1 = src.iff1_; + registers.iff2 = src.iff2_; + + // Inputs. + inputs.irq = src.irq_line_; + inputs.nmi = src.nmi_line_; + inputs.wait = src.wait_line_; + inputs.bus_request = src.bus_request_line_; +} + +void State::apply(ProcessorBase &target) { + // Registers. + target.a_ = registers.a; + target.set_flags(registers.flags); + target.bc_.full = registers.bc; + target.de_.full = registers.de; + target.hl_.full = registers.hl; + target.bcDash_.full = registers.bcDash; + target.deDash_.full = registers.deDash; + target.hlDash_.full = registers.hlDash; + target.ix_.full = registers.ix; + target.iy_.full = registers.iy; + target.ir_.full = registers.ir; + target.pc_.full = registers.program_counter; + target.sp_.full = registers.stack_pointer; + target.memptr_.full = registers.memptr; + target.interrupt_mode_ = registers.interrupt_mode; + target.iff1_ = registers.iff1; + target.iff2_ = registers.iff2; + + // Inputs. + target.irq_line_ = inputs.irq; + target.nmi_line_ = inputs.nmi; + target.wait_line_ = inputs.wait; + target.bus_request_line_ = inputs.bus_request; +} + +// 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(a); + DeclareField(flags); + DeclareField(bc); + DeclareField(de); + DeclareField(hl); + DeclareField(bcDash); + DeclareField(deDash); + DeclareField(hlDash); + DeclareField(ix); + DeclareField(iy); + DeclareField(ir); + DeclareField(program_counter); + DeclareField(stack_pointer); + DeclareField(interrupt_mode); + DeclareField(iff1); + DeclareField(iff2); + DeclareField(memptr); + } +} + +State::ExecutionState::ExecutionState() { + if(needs_declare()) { + } +} + +State::Inputs::Inputs() { + if(needs_declare()) { + DeclareField(irq); + DeclareField(nmi); + DeclareField(bus_request); + DeclareField(wait); + } +} diff --git a/Processors/Z80/State/State.hpp b/Processors/Z80/State/State.hpp new file mode 100644 index 000000000..35f31d941 --- /dev/null +++ b/Processors/Z80/State/State.hpp @@ -0,0 +1,80 @@ +// +// State.hpp +// Clock Signal +// +// Created by Thomas Harte on 13/05/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#ifndef State_hpp +#define State_hpp + +#include "../../../Reflection/Enum.hpp" +#include "../../../Reflection/Struct.hpp" +#include "../Z80.hpp" + +namespace CPU { +namespace Z80 { + +/*! + Provides a means for capturing or restoring complete Z80 state. + + This is an optional adjunct to the Z80 class. If you want to take the rest of the Z80 + 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 { + uint8_t a; + uint8_t flags; + uint16_t bc, de, hl; + uint16_t bcDash, deDash, hlDash; + uint16_t ix, iy, ir; + uint16_t program_counter, stack_pointer; + uint16_t memptr; + int interrupt_mode; + bool iff1, iff2; + + 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 irq; + bool nmi; + bool bus_request; + bool wait; + + 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 { + + 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_hpp */