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/OSBindings/SDL/SConstruct b/OSBindings/SDL/SConstruct index d659e5e5e..e644eec10 100644 --- a/OSBindings/SDL/SConstruct +++ b/OSBindings/SDL/SConstruct @@ -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') 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..91577739d 100644 --- a/Processors/Z80/Implementation/Z80Storage.hpp +++ b/Processors/Z80/Implementation/Z80Storage.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 &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; }; diff --git a/Processors/Z80/State/State.cpp b/Processors/Z80/State/State.cpp new file mode 100644 index 000000000..bcba268f9 --- /dev/null +++ b/Processors/Z80/State/State.cpp @@ -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 + +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(); + + // 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); + } +} diff --git a/Processors/Z80/State/State.hpp b/Processors/Z80/State/State.hpp new file mode 100644 index 000000000..05c210420 --- /dev/null +++ b/Processors/Z80/State/State.hpp @@ -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 { + /*! + 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 = 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 { + 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 */ diff --git a/Reflection/Struct.cpp b/Reflection/Struct.cpp index 0c175c431..2a2d80736 100644 --- a/Reflection/Struct.cpp +++ b/Reflection/Struct.cpp @@ -11,6 +11,7 @@ #include #include #include +#include // MARK: - Setters @@ -113,11 +114,20 @@ template 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::value && sizeof(Type) == sizeof(int)) { + if(!Enum::name(*target_type).empty()) { + memcpy(&value, target.get(name), sizeof(int)); + return true; + } + } + return false; }