2016-07-01 14:01:06 +01:00
|
|
|
/* 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
|
|
|
|
|
2016-12-11 15:38:00 +00:00
|
|
|
#include <memory>
|
2016-08-31 21:09:26 +01:00
|
|
|
#include <type_traits>
|
2016-12-11 15:38:00 +00:00
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
#include <xbyak.h>
|
2017-11-02 19:58:40 +00:00
|
|
|
#include <xbyak_util.h>
|
2016-08-13 00:10:23 +01:00
|
|
|
|
2017-03-18 17:20:21 +00:00
|
|
|
#include "backend_x64/constant_pool.h"
|
2016-07-01 14:01:06 +01:00
|
|
|
#include "backend_x64/jitstate.h"
|
|
|
|
#include "common/common_types.h"
|
2016-09-01 00:06:40 +01:00
|
|
|
#include "dynarmic/callbacks.h"
|
2016-07-01 14:01:06 +01:00
|
|
|
|
|
|
|
namespace Dynarmic {
|
|
|
|
namespace BackendX64 {
|
|
|
|
|
2017-04-07 10:52:44 +01:00
|
|
|
using LookupBlockCallback = CodePtr(*)(void*);
|
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
class BlockOfCode final : public Xbyak::CodeGenerator {
|
2016-07-01 14:01:06 +01:00
|
|
|
public:
|
2017-04-07 10:52:44 +01:00
|
|
|
BlockOfCode(UserCallbacks cb, LookupBlockCallback lookup_block, void* lookup_block_arg);
|
2016-08-07 18:08:48 +01:00
|
|
|
|
2016-08-12 18:17:31 +01:00
|
|
|
/// Clears this block of code and resets code pointer to beginning.
|
2016-09-01 09:47:09 +01:00
|
|
|
void ClearCache();
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2016-08-12 18:17:31 +01:00
|
|
|
/// Runs emulated code for approximately `cycles_to_run` cycles.
|
2017-04-07 10:52:44 +01:00
|
|
|
size_t RunCode(JitState* jit_state, size_t cycles_to_run) const;
|
|
|
|
/// Code emitter: Returns to dispatcher
|
2016-08-07 22:47:17 +01:00
|
|
|
void ReturnFromRunCode(bool MXCSR_switch = true);
|
2017-04-07 10:52:44 +01:00
|
|
|
/// Code emitter: Returns to dispatcher, forces return to host
|
|
|
|
void ForceReturnFromRunCode(bool MXCSR_switch = true);
|
2016-08-12 18:17:31 +01:00
|
|
|
/// Code emitter: Makes guest MXCSR the current MXCSR
|
2016-08-07 22:47:17 +01:00
|
|
|
void SwitchMxcsrOnEntry();
|
2016-08-12 18:17:31 +01:00
|
|
|
/// Code emitter: Makes saved host MXCSR the current MXCSR
|
2016-08-07 22:47:17 +01:00
|
|
|
void SwitchMxcsrOnExit();
|
2016-08-31 21:09:26 +01:00
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
/// Code emitter: Calls the function
|
2016-08-31 21:09:26 +01:00
|
|
|
template <typename FunctionPointer>
|
|
|
|
void CallFunction(FunctionPointer fn) {
|
|
|
|
static_assert(std::is_pointer<FunctionPointer>() && std::is_function<std::remove_pointer_t<FunctionPointer>>(),
|
|
|
|
"Supplied type must be a pointer to a function");
|
|
|
|
|
|
|
|
const u64 address = reinterpret_cast<u64>(fn);
|
|
|
|
const u64 distance = address - (getCurr<u64>() + 5);
|
|
|
|
|
2017-11-02 20:07:01 +00:00
|
|
|
// As we do not know if user-code is AVX or SSE, an AVX-SSE transition may occur.
|
|
|
|
// We avoid the transition penalty by calling vzeroupper.
|
|
|
|
if (DoesCpuSupport(Xbyak::util::Cpu::tAVX)) {
|
|
|
|
vzeroupper();
|
|
|
|
}
|
|
|
|
|
2016-08-31 21:09:26 +01:00
|
|
|
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
|
|
|
// Far call
|
|
|
|
mov(rax, address);
|
|
|
|
call(rax);
|
|
|
|
} else {
|
|
|
|
call(fn);
|
|
|
|
}
|
|
|
|
}
|
2016-08-07 18:08:48 +01:00
|
|
|
|
2017-03-18 17:20:21 +00:00
|
|
|
Xbyak::Address MConst(u64 constant);
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2017-04-19 18:58:36 +01:00
|
|
|
/// Far code sits far away from the near code. Execution remains primarily in near code.
|
|
|
|
/// "Cold" / Rarely executed instructions sit in far code, so the CPU doesn't fetch them unless necessary.
|
|
|
|
void SwitchToFarCode();
|
|
|
|
void SwitchToNearCode();
|
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
const void* GetReturnFromRunCodeAddress() const {
|
2017-04-07 10:52:44 +01:00
|
|
|
return return_from_run_code[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
const void* GetForceReturnFromRunCodeAddress() const {
|
|
|
|
return return_from_run_code[FORCE_RETURN];
|
2016-08-13 00:10:23 +01:00
|
|
|
}
|
|
|
|
|
2016-09-01 00:06:40 +01:00
|
|
|
const void* GetMemoryReadCallback(size_t bit_size) const {
|
|
|
|
switch (bit_size) {
|
|
|
|
case 8:
|
|
|
|
return read_memory_8;
|
|
|
|
case 16:
|
|
|
|
return read_memory_16;
|
|
|
|
case 32:
|
|
|
|
return read_memory_32;
|
|
|
|
case 64:
|
|
|
|
return read_memory_64;
|
|
|
|
default:
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const void* GetMemoryWriteCallback(size_t bit_size) const {
|
|
|
|
switch (bit_size) {
|
|
|
|
case 8:
|
|
|
|
return write_memory_8;
|
|
|
|
case 16:
|
|
|
|
return write_memory_16;
|
|
|
|
case 32:
|
|
|
|
return write_memory_32;
|
|
|
|
case 64:
|
|
|
|
return write_memory_64;
|
|
|
|
default:
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
void int3() { db(0xCC); }
|
|
|
|
|
2016-12-16 20:48:08 +00:00
|
|
|
/// Allocate memory of `size` bytes from the same block of memory the code is in.
|
|
|
|
/// This is useful for objects that need to be placed close to or within code.
|
|
|
|
/// The lifetime of this memory is the same as the code around it.
|
|
|
|
void* AllocateFromCodeSpace(size_t size);
|
|
|
|
|
2016-09-04 11:30:57 +01:00
|
|
|
void SetCodePtr(CodePtr code_ptr);
|
2016-08-24 20:07:08 +01:00
|
|
|
void EnsurePatchLocationSize(CodePtr begin, size_t size);
|
|
|
|
|
2017-09-29 01:35:24 +01:00
|
|
|
static const Xbyak::Reg64 ABI_RETURN;
|
|
|
|
static const Xbyak::Reg64 ABI_PARAM1;
|
|
|
|
static const Xbyak::Reg64 ABI_PARAM2;
|
|
|
|
static const Xbyak::Reg64 ABI_PARAM3;
|
|
|
|
static const Xbyak::Reg64 ABI_PARAM4;
|
2016-08-24 20:07:08 +01:00
|
|
|
|
2017-11-02 19:58:40 +00:00
|
|
|
bool DoesCpuSupport(Xbyak::util::Cpu::Type type) const;
|
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
private:
|
2016-09-01 00:06:40 +01:00
|
|
|
UserCallbacks cb;
|
2017-04-07 10:52:44 +01:00
|
|
|
LookupBlockCallback lookup_block;
|
|
|
|
void* lookup_block_arg;
|
|
|
|
|
2017-04-19 18:58:36 +01:00
|
|
|
CodePtr near_code_begin;
|
|
|
|
CodePtr far_code_begin;
|
2016-09-01 00:06:40 +01:00
|
|
|
|
2017-03-18 17:20:21 +00:00
|
|
|
ConstantPool constant_pool;
|
2016-08-06 17:12:40 +01:00
|
|
|
|
2017-04-19 18:58:36 +01:00
|
|
|
bool in_far_code = false;
|
|
|
|
CodePtr near_code_ptr;
|
|
|
|
CodePtr far_code_ptr;
|
|
|
|
|
2017-04-07 10:52:44 +01:00
|
|
|
using RunCodeFuncType = void(*)(JitState*);
|
2016-08-22 15:35:07 +01:00
|
|
|
RunCodeFuncType run_code = nullptr;
|
2017-04-07 10:52:44 +01:00
|
|
|
static constexpr size_t NO_SWITCH_MXCSR = 1 << 0;
|
|
|
|
static constexpr size_t FORCE_RETURN = 1 << 1;
|
|
|
|
std::array<const void*, 4> return_from_run_code;
|
2016-07-01 14:01:06 +01:00
|
|
|
void GenRunCode();
|
2016-08-13 00:10:23 +01:00
|
|
|
|
2016-09-01 00:06:40 +01:00
|
|
|
const void* read_memory_8 = nullptr;
|
|
|
|
const void* read_memory_16 = nullptr;
|
|
|
|
const void* read_memory_32 = nullptr;
|
|
|
|
const void* read_memory_64 = nullptr;
|
|
|
|
const void* write_memory_8 = nullptr;
|
|
|
|
const void* write_memory_16 = nullptr;
|
|
|
|
const void* write_memory_32 = nullptr;
|
|
|
|
const void* write_memory_64 = nullptr;
|
|
|
|
void GenMemoryAccessors();
|
2016-12-11 15:38:00 +00:00
|
|
|
|
2017-04-20 14:08:56 +01:00
|
|
|
class ExceptionHandler final {
|
2016-12-11 15:38:00 +00:00
|
|
|
public:
|
2017-04-20 14:08:56 +01:00
|
|
|
ExceptionHandler();
|
|
|
|
~ExceptionHandler();
|
2016-12-11 15:38:00 +00:00
|
|
|
|
|
|
|
void Register(BlockOfCode* code);
|
|
|
|
private:
|
|
|
|
struct Impl;
|
|
|
|
std::unique_ptr<Impl> impl;
|
|
|
|
};
|
2017-04-20 14:08:56 +01:00
|
|
|
ExceptionHandler exception_handler;
|
2017-11-02 19:58:40 +00:00
|
|
|
|
|
|
|
Xbyak::util::Cpu cpu_info;
|
2016-07-01 14:01:06 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace BackendX64
|
|
|
|
} // namespace Dynarmic
|