1 // Copyright 2016 Dolphin Emulator Project 2 // Licensed under GPLv2+ 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <unordered_map> 8 9 #include "Common/BitSet.h" 10 #include "Common/CommonTypes.h" 11 #include "Common/x64Emitter.h" 12 13 #include "Core/PowerPC/Jit64Common/ConstantPool.h" 14 #include "Core/PowerPC/Jit64Common/FarCodeCache.h" 15 #include "Core/PowerPC/Jit64Common/TrampolineInfo.h" 16 17 namespace MMIO 18 { 19 class Mapping; 20 } 21 22 class Jit64; 23 24 // Like XCodeBlock but has some utilities for memory access. 25 class EmuCodeBlock : public Gen::X64CodeBlock 26 { 27 public: EmuCodeBlock(Jit64 & jit)28 explicit EmuCodeBlock(Jit64& jit) : m_jit{jit} {} 29 void MemoryExceptionCheck(); 30 31 // Simple functions to switch between near and far code emitting 32 void SwitchToFarCode(); 33 void SwitchToNearCode(); 34 35 template <typename T> GetConstantFromPool(const T & value)36 const void* GetConstantFromPool(const T& value) 37 { 38 return m_const_pool.GetConstant(&value, sizeof(T), 1, 0); 39 } 40 41 template <typename T> MConst(const T & value)42 Gen::OpArg MConst(const T& value) 43 { 44 return Gen::M(GetConstantFromPool(value)); 45 } 46 47 template <typename T, size_t N> 48 Gen::OpArg MConst(const T (&value)[N], size_t index = 0) 49 { 50 return Gen::M(m_const_pool.GetConstant(&value, sizeof(T), N, index)); 51 } 52 53 Gen::FixupBranch CheckIfSafeAddress(const Gen::OpArg& reg_value, Gen::X64Reg reg_addr, 54 BitSet32 registers_in_use); 55 void UnsafeLoadRegToReg(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, 56 s32 offset = 0, bool signExtend = false); 57 void UnsafeLoadRegToRegNoSwap(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize, 58 s32 offset, bool signExtend = false); 59 // these return the address of the MOV, for backpatching 60 void UnsafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, 61 s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr); 62 void UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, 63 s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr); 64 65 bool UnsafeLoadToReg(Gen::X64Reg reg_value, Gen::OpArg opAddress, int accessSize, s32 offset, 66 bool signExtend, Gen::MovInfo* info = nullptr); 67 68 // Generate a load/write from the MMIO handler for a given address. Only 69 // call for known addresses in MMIO range (MMIO::IsMMIOAddress). 70 void MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value, BitSet32 registers_in_use, 71 u32 address, int access_size, bool sign_extend); 72 73 enum SafeLoadStoreFlags 74 { 75 SAFE_LOADSTORE_NO_SWAP = 1, 76 SAFE_LOADSTORE_NO_PROLOG = 2, 77 // This indicates that the write being generated cannot be patched (and thus can't use fastmem) 78 SAFE_LOADSTORE_NO_FASTMEM = 4, 79 SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR = 8, 80 // Force slowmem (used when generating fallbacks in trampolines) 81 SAFE_LOADSTORE_FORCE_SLOWMEM = 16, 82 SAFE_LOADSTORE_DR_ON = 32, 83 // Generated from a context that doesn't have the PC of the instruction that caused it 84 SAFE_LOADSTORE_NO_UPDATE_PC = 64, 85 }; 86 87 void SafeLoadToReg(Gen::X64Reg reg_value, const Gen::OpArg& opAddress, int accessSize, s32 offset, 88 BitSet32 registersInUse, bool signExtend, int flags = 0); 89 void SafeLoadToRegImmediate(Gen::X64Reg reg_value, u32 address, int accessSize, 90 BitSet32 registersInUse, bool signExtend); 91 92 // Clobbers RSCRATCH or reg_addr depending on the relevant flag. Preserves 93 // reg_value if the load fails and js.memcheck is enabled. 94 // Works with immediate inputs and simple registers only. 95 void SafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, 96 BitSet32 registersInUse, int flags = 0); 97 void SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset, 98 BitSet32 registersInUse, int flags = 0); 99 100 // applies to safe and unsafe WriteRegToReg 101 bool WriteClobbersRegValue(int accessSize, bool swap); 102 103 // returns true if an exception could have been caused 104 bool WriteToConstAddress(int accessSize, Gen::OpArg arg, u32 address, BitSet32 registersInUse); 105 void WriteToConstRamAddress(int accessSize, Gen::OpArg arg, u32 address, bool swap = true); 106 107 void JitGetAndClearCAOV(bool oe); 108 void JitSetCA(); 109 void JitSetCAIf(Gen::CCFlags conditionCode); 110 void JitClearCA(); 111 112 void avx_op(void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&), 113 void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&), Gen::X64Reg regOp, 114 const Gen::OpArg& arg1, const Gen::OpArg& arg2, bool packed = true, 115 bool reversible = false); 116 void avx_op(void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&, u8), 117 void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&, u8), Gen::X64Reg regOp, 118 const Gen::OpArg& arg1, const Gen::OpArg& arg2, u8 imm); 119 120 void ForceSinglePrecision(Gen::X64Reg output, const Gen::OpArg& input, bool packed = true, 121 bool duplicate = false); 122 void Force25BitPrecision(Gen::X64Reg output, const Gen::OpArg& input, Gen::X64Reg tmp); 123 124 // RSCRATCH might get trashed 125 void ConvertSingleToDouble(Gen::X64Reg dst, Gen::X64Reg src, bool src_is_gpr = false); 126 void ConvertDoubleToSingle(Gen::X64Reg dst, Gen::X64Reg src); 127 void SetFPRF(Gen::X64Reg xmm); 128 void Clear(); 129 130 protected: 131 Jit64& m_jit; 132 ConstantPool m_const_pool; 133 FarCodeCache m_far_code; 134 135 // Backed up when we switch to far code. 136 u8* m_near_code; 137 u8* m_near_code_end; 138 bool m_near_code_write_failed; 139 140 std::unordered_map<u8*, TrampolineInfo> m_back_patch_info; 141 std::unordered_map<u8*, u8*> m_exception_handler_at_loc; 142 }; 143