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-08-31 21:09:26 +01:00
|
|
|
#include <type_traits>
|
2016-08-24 20:07:08 +01:00
|
|
|
#include <xbyak.h>
|
2016-08-13 00:10:23 +01:00
|
|
|
|
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 {
|
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
class BlockOfCode final : public Xbyak::CodeGenerator {
|
2016-07-01 14:01:06 +01:00
|
|
|
public:
|
2016-09-01 00:06:40 +01:00
|
|
|
explicit BlockOfCode(UserCallbacks cb);
|
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.
|
2016-07-01 14:01:06 +01:00
|
|
|
size_t RunCode(JitState* jit_state, CodePtr basic_block, size_t cycles_to_run) const;
|
2016-08-12 18:17:31 +01:00
|
|
|
/// Code emitter: Returns to host
|
2016-08-07 22:47:17 +01:00
|
|
|
void ReturnFromRunCode(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);
|
|
|
|
|
|
|
|
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
|
|
|
// Far call
|
|
|
|
mov(rax, address);
|
|
|
|
call(rax);
|
|
|
|
} else {
|
|
|
|
call(fn);
|
|
|
|
}
|
|
|
|
}
|
2016-08-07 18:08:48 +01:00
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatPositiveZero32() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatPositiveZero32];
|
2016-08-22 15:35:07 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatNegativeZero32() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatNegativeZero32];
|
2016-08-06 17:12:40 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatNaN32() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatNaN32];
|
2016-08-06 17:12:40 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatNonSignMask32() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatNonSignMask32];
|
2016-08-07 01:27:18 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatPositiveZero64() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatPositiveZero64];
|
2016-08-22 15:35:07 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatNegativeZero64() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatNegativeZero64];
|
2016-08-06 17:12:40 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatNaN64() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatNaN64];
|
2016-08-06 17:12:40 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatNonSignMask64() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatNonSignMask64];
|
2016-08-06 17:12:40 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatPenultimatePositiveDenormal64() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatPenultimatePositiveDenormal64];
|
2016-08-06 17:12:40 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatMinS32() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatMinS32];
|
2016-08-22 15:35:07 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatMaxS32() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatMaxS32];
|
2016-08-22 15:35:07 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatMinU32() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatMinU32];
|
2016-08-22 15:35:07 +01:00
|
|
|
}
|
2016-08-24 20:07:08 +01:00
|
|
|
Xbyak::Address MFloatMaxU32() {
|
2016-08-25 02:59:42 +01:00
|
|
|
return xword[rip + consts.FloatMaxU32];
|
2016-08-22 15:35:07 +01:00
|
|
|
}
|
2016-07-01 14:01:06 +01:00
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
const void* GetReturnFromRunCodeAddress() const {
|
2016-08-13 00:10:23 +01:00
|
|
|
return return_from_run_code;
|
|
|
|
}
|
|
|
|
|
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-08-27 10:57:48 +01:00
|
|
|
void nop(size_t size = 1);
|
2016-08-24 20:07:08 +01:00
|
|
|
|
|
|
|
void SetCodePtr(CodePtr ptr);
|
|
|
|
void EnsurePatchLocationSize(CodePtr begin, size_t size);
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
Xbyak::Reg64 ABI_RETURN = rax;
|
|
|
|
Xbyak::Reg64 ABI_PARAM1 = rcx;
|
|
|
|
Xbyak::Reg64 ABI_PARAM2 = rdx;
|
|
|
|
Xbyak::Reg64 ABI_PARAM3 = r8;
|
|
|
|
Xbyak::Reg64 ABI_PARAM4 = r9;
|
|
|
|
#else
|
|
|
|
Xbyak::Reg64 ABI_RETURN = rax;
|
|
|
|
Xbyak::Reg64 ABI_PARAM1 = rdi;
|
|
|
|
Xbyak::Reg64 ABI_PARAM2 = rsi;
|
|
|
|
Xbyak::Reg64 ABI_PARAM3 = rdx;
|
|
|
|
Xbyak::Reg64 ABI_PARAM4 = rcx;
|
|
|
|
#endif
|
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
private:
|
2016-09-01 00:06:40 +01:00
|
|
|
UserCallbacks cb;
|
|
|
|
|
2016-08-25 02:59:42 +01:00
|
|
|
struct Consts {
|
|
|
|
Xbyak::Label FloatPositiveZero32;
|
|
|
|
Xbyak::Label FloatNegativeZero32;
|
|
|
|
Xbyak::Label FloatNaN32;
|
|
|
|
Xbyak::Label FloatNonSignMask32;
|
|
|
|
Xbyak::Label FloatPositiveZero64;
|
|
|
|
Xbyak::Label FloatNegativeZero64;
|
|
|
|
Xbyak::Label FloatNaN64;
|
|
|
|
Xbyak::Label FloatNonSignMask64;
|
|
|
|
Xbyak::Label FloatPenultimatePositiveDenormal64;
|
|
|
|
Xbyak::Label FloatMinS32;
|
|
|
|
Xbyak::Label FloatMaxS32;
|
|
|
|
Xbyak::Label FloatMinU32;
|
|
|
|
Xbyak::Label FloatMaxU32;
|
|
|
|
} consts;
|
2016-08-06 17:12:40 +01:00
|
|
|
void GenConstants();
|
|
|
|
|
2016-07-01 14:01:06 +01:00
|
|
|
using RunCodeFuncType = void(*)(JitState*, CodePtr);
|
2016-08-22 15:35:07 +01:00
|
|
|
RunCodeFuncType run_code = nullptr;
|
2016-07-01 14:01:06 +01:00
|
|
|
void GenRunCode();
|
2016-08-13 00:10:23 +01:00
|
|
|
|
2016-08-24 20:07:08 +01:00
|
|
|
const void* return_from_run_code = nullptr;
|
|
|
|
const void* return_from_run_code_without_mxcsr_switch = nullptr;
|
2016-08-13 00:10:23 +01:00
|
|
|
void GenReturnFromRunCode();
|
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-07-01 14:01:06 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace BackendX64
|
|
|
|
} // namespace Dynarmic
|