diff --git a/include/dynarmic/context.h b/include/dynarmic/context.h new file mode 100644 index 00000000..8276a8ae --- /dev/null +++ b/include/dynarmic/context.h @@ -0,0 +1,44 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2016 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include +#include +#include + +namespace Dynarmic { + +struct Context { +public: + Context(); + ~Context(); + Context(const Context&); + Context(Context&&); + Context& operator=(const Context&); + Context& operator=(Context&&); + + /// View and modify registers. + std::array& Regs(); + const std::array& Regs() const; + std::array& ExtRegs(); + const std::array& ExtRegs() const; + + /// View and modify CPSR. + std::uint32_t Cpsr() const; + void SetCpsr(std::uint32_t value); + + /// View and modify FPSCR. + std::uint32_t Fpscr() const; + void SetFpscr(std::uint32_t value); + +private: + friend class Jit; + struct Impl; + std::unique_ptr impl; +}; + +} // namespace Dynarmic diff --git a/include/dynarmic/dynarmic.h b/include/dynarmic/dynarmic.h index d5b82886..1bfcc2a0 100644 --- a/include/dynarmic/dynarmic.h +++ b/include/dynarmic/dynarmic.h @@ -15,6 +15,8 @@ namespace Dynarmic { +struct Context; + namespace IR { class LocationDescriptor; } @@ -70,6 +72,10 @@ public: std::uint32_t Fpscr() const; void SetFpscr(std::uint32_t value); + Context SaveContext() const; + void SaveContext(Context&) const; + void LoadContext(const Context&); + /** * Returns true if Jit::Run was called but hasn't returned yet. * i.e.: We're in a callback. diff --git a/src/backend_x64/interface_x64.cpp b/src/backend_x64/interface_x64.cpp index ad991a36..945391fe 100644 --- a/src/backend_x64/interface_x64.cpp +++ b/src/backend_x64/interface_x64.cpp @@ -20,6 +20,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/scope_exit.h" +#include "dynarmic/context.h" #include "dynarmic/dynarmic.h" #include "frontend/ir/basic_block.h" #include "frontend/ir/location_descriptor.h" @@ -45,6 +46,7 @@ struct Jit::Impl { const UserCallbacks callbacks; // Requests made during execution to invalidate the cache are queued up here. + size_t invalid_cache_generation = 0; boost::icl::interval_set invalid_cache_ranges; bool invalidate_entire_cache = false; @@ -98,6 +100,7 @@ struct Jit::Impl { invalid_cache_ranges.clear(); invalidate_entire_cache = false; + invalid_cache_generation++; return; } @@ -108,6 +111,7 @@ struct Jit::Impl { jit_state.ResetRSB(); emitter.InvalidateCacheRanges(invalid_cache_ranges); invalid_cache_ranges.clear(); + invalid_cache_generation++; } void RequestCacheInvalidation() { @@ -221,6 +225,91 @@ void Jit::SetFpscr(u32 value) { return impl->jit_state.SetFpscr(value); } +Context Jit::SaveContext() const { + Context ctx; + SaveContext(ctx); + return ctx; +} + +struct Context::Impl { + JitState jit_state; + size_t invalid_cache_generation; +}; + +Context::Context() : impl(std::make_unique()) { impl->jit_state.ResetRSB(); } +Context::~Context() = default; +Context::Context(const Context& ctx) : impl(std::make_unique(*ctx.impl)) {} +Context::Context(Context&& ctx) : impl(std::move(ctx.impl)) {} +Context& Context::operator=(const Context& ctx) { + *impl = *ctx.impl; + return *this; +} +Context& Context::operator=(Context&& ctx) { + impl = std::move(ctx.impl); + return *this; +} + +std::array& Context::Regs() { + return impl->jit_state.Reg; +} +const std::array& Context::Regs() const { + return impl->jit_state.Reg; +} +std::array& Context::ExtRegs() { + return impl->jit_state.ExtReg; +} +const std::array& Context::ExtRegs() const { + return impl->jit_state.ExtReg; +} + +/// View and modify CPSR. +std::uint32_t Context::Cpsr() const { + return impl->jit_state.Cpsr(); +} +void Context::SetCpsr(std::uint32_t value) { + impl->jit_state.SetCpsr(value); +} + +/// View and modify FPSCR. +std::uint32_t Context::Fpscr() const { + return impl->jit_state.Fpscr(); +} +void Context::SetFpscr(std::uint32_t value) { + return impl->jit_state.SetFpscr(value); +} + +void TransferJitState(JitState& dest, const JitState& src, bool reset_rsb) { + dest.CPSR_ge = src.CPSR_ge; + dest.CPSR_et = src.CPSR_et; + dest.CPSR_q = src.CPSR_q; + dest.CPSR_nzcv = src.CPSR_nzcv; + dest.CPSR_jaifm = src.CPSR_jaifm; + dest.Reg = src.Reg; + dest.ExtReg = src.ExtReg; + dest.guest_MXCSR = src.guest_MXCSR; + dest.FPSCR_IDC = src.FPSCR_IDC; + dest.FPSCR_UFC = src.FPSCR_UFC; + dest.FPSCR_mode = src.FPSCR_mode; + dest.FPSCR_nzcv = src.FPSCR_nzcv; + if (reset_rsb) { + dest.ResetRSB(); + } else { + dest.rsb_ptr = src.rsb_ptr; + dest.rsb_location_descriptors = src.rsb_location_descriptors; + dest.rsb_codeptrs = src.rsb_codeptrs; + } +} + +void Jit::SaveContext(Context& ctx) const { + TransferJitState(ctx.impl->jit_state, impl->jit_state, false); + ctx.impl->invalid_cache_generation = impl->invalid_cache_generation; +} + +void Jit::LoadContext(const Context& ctx) { + bool reset_rsb = ctx.impl->invalid_cache_generation != impl->invalid_cache_generation; + TransferJitState(impl->jit_state, ctx.impl->jit_state, reset_rsb); +} + std::string Jit::Disassemble(const IR::LocationDescriptor& descriptor) { return impl->Disassemble(descriptor); } diff --git a/src/frontend/translate/translate_thumb.cpp b/src/frontend/translate/translate_thumb.cpp index 6a173274..1062d436 100644 --- a/src/frontend/translate/translate_thumb.cpp +++ b/src/frontend/translate/translate_thumb.cpp @@ -682,7 +682,7 @@ struct ThumbTranslatorVisitor final { ir.LoadWritePC(data); address = ir.Add(address, ir.Imm32(4)); ir.SetRegister(Reg::SP, address); - ir.SetTerm(IR::Term::ReturnToDispatch{}); + ir.SetTerm(IR::Term::PopRSBHint{}); return false; } else { ir.SetRegister(Reg::SP, address);