mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Merge pull request #793 from TomHarte/Z80State
Adds reflective state for the Z80.
This commit is contained in:
commit
4f30118b37
@ -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 = "<group>"; };
|
||||
4B17B58920A8A9D9007CCA8F /* StringSerialiser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StringSerialiser.cpp; sourceTree = "<group>"; };
|
||||
4B17B58A20A8A9D9007CCA8F /* StringSerialiser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StringSerialiser.hpp; sourceTree = "<group>"; };
|
||||
4B1B58F4246CC4E8009C171E /* State.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = State.cpp; sourceTree = "<group>"; };
|
||||
4B1B58F5246CC4E8009C171E /* State.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = State.hpp; sourceTree = "<group>"; };
|
||||
4B1B88B9202E2EC100B67DFF /* MultiKeyboardMachine.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiKeyboardMachine.cpp; sourceTree = "<group>"; };
|
||||
4B1B88BA202E2EC100B67DFF /* MultiKeyboardMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiKeyboardMachine.hpp; sourceTree = "<group>"; };
|
||||
4B1B88BE202E3DB200B67DFF /* MultiConfigurable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiConfigurable.cpp; sourceTree = "<group>"; };
|
||||
@ -2008,6 +2012,16 @@
|
||||
name = Cartridges;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B1B58F3246CC4E8009C171E /* State */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B1B58F4246CC4E8009C171E /* State.cpp */,
|
||||
4B1B58F5246CC4E8009C171E /* State.hpp */,
|
||||
);
|
||||
name = State;
|
||||
path = Z80/State;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B1E85791D174DEC001EF87D /* 6532 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -2630,6 +2644,7 @@
|
||||
4B77069C1EC904570053B588 /* Z80.hpp */,
|
||||
4B322DFC1F5A2981004EB04C /* AllRAM */,
|
||||
4B322DFF1F5A2981004EB04C /* Implementation */,
|
||||
4B1B58F3246CC4E8009C171E /* State */,
|
||||
);
|
||||
name = Z80;
|
||||
sourceTree = "<group>";
|
||||
@ -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 */,
|
||||
|
@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:Clock Signal.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
@ -86,6 +86,7 @@ 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')
|
||||
SOURCES += glob.glob('../../Processors/Z80/State/*.cpp')
|
||||
|
||||
SOURCES += glob.glob('../../Reflection/*.cpp')
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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<State> {
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* State_h */
|
||||
#endif /* State_hpp */
|
||||
|
@ -127,8 +127,6 @@ class ProcessorStorage {
|
||||
InstructionPage() : r_step(1), is_indexed(false) {}
|
||||
};
|
||||
|
||||
typedef MicroOp InstructionTable[256][30];
|
||||
|
||||
ProcessorStorage();
|
||||
void install_default_instruction_set();
|
||||
|
||||
@ -195,8 +193,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 +202,6 @@ class ProcessorStorage {
|
||||
(parity_overflow_result_ & Flag::Parity) |
|
||||
subtract_flag_ |
|
||||
(carry_result_ & Flag::Carry);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -224,6 +221,7 @@ class ProcessorStorage {
|
||||
carry_result_ = flags;
|
||||
}
|
||||
|
||||
typedef MicroOp InstructionTable[256][30];
|
||||
virtual void assemble_page(InstructionPage &target, InstructionTable &table, bool add_offsets) = 0;
|
||||
virtual void copy_program(const MicroOp *source, std::vector<MicroOp> &destination) = 0;
|
||||
|
||||
@ -232,4 +230,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;
|
||||
};
|
||||
|
222
Processors/Z80/State/State.cpp
Normal file
222
Processors/Z80/State/State.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
//
|
||||
// State.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 13/05/2020.
|
||||
// Copyright © 2020 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "State.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
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_;
|
||||
|
||||
// Execution State.
|
||||
execution_state.is_halted = src.halt_mask_ == 0x00;
|
||||
execution_state.requests = src.request_status_;
|
||||
execution_state.last_requests = src.last_request_status_;
|
||||
execution_state.temp8 = src.temp8_;
|
||||
execution_state.temp16 = src.temp16_.full;
|
||||
execution_state.operation = src.operation_;
|
||||
execution_state.flag_adjustment_history = src.flag_adjustment_history_;
|
||||
execution_state.pc_increment = src.pc_increment_;
|
||||
execution_state.refresh_address = src.refresh_addr_.full;
|
||||
execution_state.half_cycles_into_step = src.number_of_cycles_.as<int>();
|
||||
|
||||
// Search for the current holder of the scheduled_program_counter_.
|
||||
#define ContainedBy(x) (src.scheduled_program_counter_ >= &src.x[0]) && (src.scheduled_program_counter_ < &src.x[src.x.size()])
|
||||
#define Populate(x, y) \
|
||||
execution_state.phase = ExecutionState::Phase::x; \
|
||||
execution_state.steps_into_phase = int(src.scheduled_program_counter_ - &src.y[0]);
|
||||
|
||||
if(ContainedBy(conditional_call_untaken_program_)) {
|
||||
Populate(UntakenConditionalCall, conditional_call_untaken_program_);
|
||||
} else if(ContainedBy(reset_program_)) {
|
||||
Populate(Reset, reset_program_);
|
||||
} else if(ContainedBy(irq_program_[0])) {
|
||||
Populate(IRQMode0, irq_program_[0]);
|
||||
} else if(ContainedBy(irq_program_[1])) {
|
||||
Populate(IRQMode1, irq_program_[1]);
|
||||
} else if(ContainedBy(irq_program_[2])) {
|
||||
Populate(IRQMode2, irq_program_[2]);
|
||||
} else if(ContainedBy(nmi_program_)) {
|
||||
Populate(NMI, nmi_program_);
|
||||
} else {
|
||||
if(src.current_instruction_page_ == &src.base_page_) {
|
||||
execution_state.instruction_page = 0;
|
||||
} else if(src.current_instruction_page_ == &src.ed_page_) {
|
||||
execution_state.instruction_page = 0xed;
|
||||
} else if(src.current_instruction_page_ == &src.fd_page_) {
|
||||
execution_state.instruction_page = 0xfd;
|
||||
} else if(src.current_instruction_page_ == &src.dd_page_) {
|
||||
execution_state.instruction_page = 0xdd;
|
||||
} else if(src.current_instruction_page_ == &src.cb_page_) {
|
||||
execution_state.instruction_page = 0xcb;
|
||||
} else if(src.current_instruction_page_ == &src.fdcb_page_) {
|
||||
execution_state.instruction_page = 0xfdcb;
|
||||
} else if(src.current_instruction_page_ == &src.ddcb_page_) {
|
||||
execution_state.instruction_page = 0xddcb;
|
||||
}
|
||||
|
||||
if(ContainedBy(current_instruction_page_->fetch_decode_execute)) {
|
||||
Populate(FetchDecode, current_instruction_page_->fetch_decode_execute);
|
||||
} else {
|
||||
// There's no need to determine which opcode because that knowledge is already
|
||||
// contained in the dedicated opcode field.
|
||||
Populate(Operation, current_instruction_page_->instructions[src.operation_ & src.halt_mask_]);
|
||||
}
|
||||
}
|
||||
|
||||
assert(execution_state.steps_into_phase >= 0);
|
||||
|
||||
#undef Populate
|
||||
#undef ContainedBy
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// Execution State.
|
||||
target.halt_mask_ = execution_state.is_halted ? 0x00 : 0xff;
|
||||
target.request_status_ = execution_state.requests;
|
||||
target.last_request_status_ = execution_state.last_requests;
|
||||
target.temp8_ = execution_state.temp8;
|
||||
target.temp16_.full = execution_state.temp16;
|
||||
target.operation_ = execution_state.operation;
|
||||
target.flag_adjustment_history_ = execution_state.flag_adjustment_history;
|
||||
target.pc_increment_ = execution_state.pc_increment;
|
||||
target.refresh_addr_.full = execution_state.refresh_address;
|
||||
target.number_of_cycles_ = HalfCycles(execution_state.half_cycles_into_step);
|
||||
|
||||
switch(execution_state.instruction_page) {
|
||||
default: target.current_instruction_page_ = &target.base_page_; break;
|
||||
case 0xed: target.current_instruction_page_ = &target.ed_page_; break;
|
||||
case 0xdd: target.current_instruction_page_ = &target.dd_page_; break;
|
||||
case 0xcb: target.current_instruction_page_ = &target.cb_page_; break;
|
||||
case 0xfd: target.current_instruction_page_ = &target.fd_page_; break;
|
||||
case 0xfdcb: target.current_instruction_page_ = &target.fdcb_page_; break;
|
||||
case 0xddcb: target.current_instruction_page_ = &target.ddcb_page_; break;
|
||||
}
|
||||
|
||||
switch(execution_state.phase) {
|
||||
case ExecutionState::Phase::UntakenConditionalCall: target.scheduled_program_counter_ = &target.conditional_call_untaken_program_[0]; break;
|
||||
case ExecutionState::Phase::Reset: target.scheduled_program_counter_ = &target.reset_program_[0]; break;
|
||||
case ExecutionState::Phase::IRQMode0: target.scheduled_program_counter_ = &target.irq_program_[0][0]; break;
|
||||
case ExecutionState::Phase::IRQMode1: target.scheduled_program_counter_ = &target.irq_program_[1][0]; break;
|
||||
case ExecutionState::Phase::IRQMode2: target.scheduled_program_counter_ = &target.irq_program_[2][0]; break;
|
||||
case ExecutionState::Phase::NMI: target.scheduled_program_counter_ = &target.nmi_program_[0]; break;
|
||||
case ExecutionState::Phase::FetchDecode: target.scheduled_program_counter_ = &target.current_instruction_page_->fetch_decode_execute[0]; break;
|
||||
case ExecutionState::Phase::Operation: target.scheduled_program_counter_ = target.current_instruction_page_->instructions[target.operation_]; break;
|
||||
}
|
||||
target.scheduled_program_counter_ += execution_state.steps_into_phase;
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
DeclareField(is_halted);
|
||||
DeclareField(requests);
|
||||
DeclareField(last_requests);
|
||||
DeclareField(temp8);
|
||||
DeclareField(operation);
|
||||
DeclareField(temp16);
|
||||
DeclareField(flag_adjustment_history);
|
||||
DeclareField(pc_increment);
|
||||
DeclareField(refresh_address);
|
||||
|
||||
AnnounceEnum(Phase);
|
||||
DeclareField(phase);
|
||||
DeclareField(half_cycles_into_step);
|
||||
DeclareField(steps_into_phase);
|
||||
DeclareField(instruction_page);
|
||||
}
|
||||
}
|
||||
|
||||
State::Inputs::Inputs() {
|
||||
if(needs_declare()) {
|
||||
DeclareField(irq);
|
||||
DeclareField(nmi);
|
||||
DeclareField(bus_request);
|
||||
DeclareField(wait);
|
||||
}
|
||||
}
|
100
Processors/Z80/State/State.hpp
Normal file
100
Processors/Z80/State/State.hpp
Normal file
@ -0,0 +1,100 @@
|
||||
//
|
||||
// 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<State> {
|
||||
/*!
|
||||
Provides the current state of the well-known, published internal registers.
|
||||
*/
|
||||
struct Registers: public Reflection::StructImpl<Registers> {
|
||||
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<Inputs> {
|
||||
bool irq = false;
|
||||
bool nmi = false;
|
||||
bool bus_request = false;
|
||||
bool wait = false;
|
||||
|
||||
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> {
|
||||
bool is_halted;
|
||||
|
||||
uint8_t requests;
|
||||
uint8_t last_requests;
|
||||
uint8_t temp8;
|
||||
uint8_t operation;
|
||||
uint16_t temp16;
|
||||
unsigned int flag_adjustment_history;
|
||||
uint16_t pc_increment;
|
||||
uint16_t refresh_address;
|
||||
|
||||
ReflectableEnum(Phase,
|
||||
UntakenConditionalCall, Reset, IRQMode0, IRQMode1, IRQMode2,
|
||||
NMI, FetchDecode, Operation
|
||||
);
|
||||
|
||||
Phase phase;
|
||||
int half_cycles_into_step;
|
||||
int steps_into_phase;
|
||||
uint16_t instruction_page = 0;
|
||||
|
||||
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 */
|
@ -11,6 +11,7 @@
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
// MARK: - Setters
|
||||
|
||||
@ -113,11 +114,20 @@ template <typename Type> bool Reflection::get(const Struct &target, const std::s
|
||||
const auto target_type = target.type_of(name);
|
||||
if(!target_type) return false;
|
||||
|
||||
// If type is a direct match, copy.
|
||||
if(*target_type == typeid(Type)) {
|
||||
memcpy(&value, target.get(name), sizeof(Type));
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the type is a registered enum and the value type is int, copy.
|
||||
if constexpr (std::is_integral<Type>::value && sizeof(Type) == sizeof(int)) {
|
||||
if(!Enum::name(*target_type).empty()) {
|
||||
memcpy(&value, target.get(name), sizeof(int));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user