dmnt_cheat_vm.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * Copyright (c) 2018-2019 Atmosphère-NX
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. /*
  17. * Adapted by DarkLordZach for use/interaction with yuzu
  18. *
  19. * Modifications Copyright 2019 yuzu emulator team
  20. * Licensed under GPLv2 or any later version
  21. * Refer to the license.txt file included.
  22. */
  23. #pragma once
  24. #include <variant>
  25. #include <vector>
  26. #include <fmt/printf.h>
  27. #include "common/common_types.h"
  28. #include "core/memory/dmnt_cheat_types.h"
  29. namespace Memory {
  30. enum class CheatVmOpcodeType : u32 {
  31. StoreStatic = 0,
  32. BeginConditionalBlock = 1,
  33. EndConditionalBlock = 2,
  34. ControlLoop = 3,
  35. LoadRegisterStatic = 4,
  36. LoadRegisterMemory = 5,
  37. StoreStaticToAddress = 6,
  38. PerformArithmeticStatic = 7,
  39. BeginKeypressConditionalBlock = 8,
  40. // These are not implemented by Gateway's VM.
  41. PerformArithmeticRegister = 9,
  42. StoreRegisterToAddress = 10,
  43. Reserved11 = 11,
  44. // This is a meta entry, and not a real opcode.
  45. // This is to facilitate multi-nybble instruction decoding.
  46. ExtendedWidth = 12,
  47. // Extended width opcodes.
  48. BeginRegisterConditionalBlock = 0xC0,
  49. SaveRestoreRegister = 0xC1,
  50. SaveRestoreRegisterMask = 0xC2,
  51. // This is a meta entry, and not a real opcode.
  52. // This is to facilitate multi-nybble instruction decoding.
  53. DoubleExtendedWidth = 0xF0,
  54. // Double-extended width opcodes.
  55. DebugLog = 0xFFF,
  56. };
  57. enum class MemoryAccessType : u32 {
  58. MainNso = 0,
  59. Heap = 1,
  60. };
  61. enum class ConditionalComparisonType : u32 {
  62. GT = 1,
  63. GE = 2,
  64. LT = 3,
  65. LE = 4,
  66. EQ = 5,
  67. NE = 6,
  68. };
  69. enum class RegisterArithmeticType : u32 {
  70. Addition = 0,
  71. Subtraction = 1,
  72. Multiplication = 2,
  73. LeftShift = 3,
  74. RightShift = 4,
  75. // These are not supported by Gateway's VM.
  76. LogicalAnd = 5,
  77. LogicalOr = 6,
  78. LogicalNot = 7,
  79. LogicalXor = 8,
  80. None = 9,
  81. };
  82. enum class StoreRegisterOffsetType : u32 {
  83. None = 0,
  84. Reg = 1,
  85. Imm = 2,
  86. MemReg = 3,
  87. MemImm = 4,
  88. MemImmReg = 5,
  89. };
  90. enum class CompareRegisterValueType : u32 {
  91. MemoryRelAddr = 0,
  92. MemoryOfsReg = 1,
  93. RegisterRelAddr = 2,
  94. RegisterOfsReg = 3,
  95. StaticValue = 4,
  96. OtherRegister = 5,
  97. };
  98. enum class SaveRestoreRegisterOpType : u32 {
  99. Restore = 0,
  100. Save = 1,
  101. ClearSaved = 2,
  102. ClearRegs = 3,
  103. };
  104. enum class DebugLogValueType : u32 {
  105. MemoryRelAddr = 0,
  106. MemoryOfsReg = 1,
  107. RegisterRelAddr = 2,
  108. RegisterOfsReg = 3,
  109. RegisterValue = 4,
  110. };
  111. union VmInt {
  112. u8 bit8;
  113. u16 bit16;
  114. u32 bit32;
  115. u64 bit64;
  116. };
  117. struct StoreStaticOpcode {
  118. u32 bit_width{};
  119. MemoryAccessType mem_type{};
  120. u32 offset_register{};
  121. u64 rel_address{};
  122. VmInt value{};
  123. };
  124. struct BeginConditionalOpcode {
  125. u32 bit_width{};
  126. MemoryAccessType mem_type{};
  127. ConditionalComparisonType cond_type{};
  128. u64 rel_address{};
  129. VmInt value{};
  130. };
  131. struct EndConditionalOpcode {};
  132. struct ControlLoopOpcode {
  133. bool start_loop{};
  134. u32 reg_index{};
  135. u32 num_iters{};
  136. };
  137. struct LoadRegisterStaticOpcode {
  138. u32 reg_index{};
  139. u64 value{};
  140. };
  141. struct LoadRegisterMemoryOpcode {
  142. u32 bit_width{};
  143. MemoryAccessType mem_type{};
  144. u32 reg_index{};
  145. bool load_from_reg{};
  146. u64 rel_address{};
  147. };
  148. struct StoreStaticToAddressOpcode {
  149. u32 bit_width{};
  150. u32 reg_index{};
  151. bool increment_reg{};
  152. bool add_offset_reg{};
  153. u32 offset_reg_index{};
  154. u64 value{};
  155. };
  156. struct PerformArithmeticStaticOpcode {
  157. u32 bit_width{};
  158. u32 reg_index{};
  159. RegisterArithmeticType math_type{};
  160. u32 value{};
  161. };
  162. struct BeginKeypressConditionalOpcode {
  163. u32 key_mask{};
  164. };
  165. struct PerformArithmeticRegisterOpcode {
  166. u32 bit_width{};
  167. RegisterArithmeticType math_type{};
  168. u32 dst_reg_index{};
  169. u32 src_reg_1_index{};
  170. u32 src_reg_2_index{};
  171. bool has_immediate{};
  172. VmInt value{};
  173. };
  174. struct StoreRegisterToAddressOpcode {
  175. u32 bit_width{};
  176. u32 str_reg_index{};
  177. u32 addr_reg_index{};
  178. bool increment_reg{};
  179. StoreRegisterOffsetType ofs_type{};
  180. MemoryAccessType mem_type{};
  181. u32 ofs_reg_index{};
  182. u64 rel_address{};
  183. };
  184. struct BeginRegisterConditionalOpcode {
  185. u32 bit_width{};
  186. ConditionalComparisonType cond_type{};
  187. u32 val_reg_index{};
  188. CompareRegisterValueType comp_type{};
  189. MemoryAccessType mem_type{};
  190. u32 addr_reg_index{};
  191. u32 other_reg_index{};
  192. u32 ofs_reg_index{};
  193. u64 rel_address{};
  194. VmInt value{};
  195. };
  196. struct SaveRestoreRegisterOpcode {
  197. u32 dst_index{};
  198. u32 src_index{};
  199. SaveRestoreRegisterOpType op_type{};
  200. };
  201. struct SaveRestoreRegisterMaskOpcode {
  202. SaveRestoreRegisterOpType op_type{};
  203. std::array<bool, 0x10> should_operate{};
  204. };
  205. struct DebugLogOpcode {
  206. u32 bit_width{};
  207. u32 log_id{};
  208. DebugLogValueType val_type{};
  209. MemoryAccessType mem_type{};
  210. u32 addr_reg_index{};
  211. u32 val_reg_index{};
  212. u32 ofs_reg_index{};
  213. u64 rel_address{};
  214. };
  215. struct UnrecognizedInstruction {
  216. CheatVmOpcodeType opcode{};
  217. };
  218. struct CheatVmOpcode {
  219. bool begin_conditional_block{};
  220. std::variant<StoreStaticOpcode, BeginConditionalOpcode, EndConditionalOpcode, ControlLoopOpcode,
  221. LoadRegisterStaticOpcode, LoadRegisterMemoryOpcode, StoreStaticToAddressOpcode,
  222. PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
  223. PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
  224. BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
  225. SaveRestoreRegisterMaskOpcode, DebugLogOpcode, UnrecognizedInstruction>
  226. opcode{};
  227. };
  228. class DmntCheatVm {
  229. public:
  230. /// Helper Type for DmntCheatVm <=> yuzu Interface
  231. class Callbacks {
  232. public:
  233. virtual ~Callbacks();
  234. virtual void MemoryRead(VAddr address, void* data, u64 size) = 0;
  235. virtual void MemoryWrite(VAddr address, const void* data, u64 size) = 0;
  236. virtual u64 HidKeysDown() = 0;
  237. virtual void DebugLog(u8 id, u64 value) = 0;
  238. virtual void CommandLog(std::string_view data) = 0;
  239. };
  240. static constexpr std::size_t MaximumProgramOpcodeCount = 0x400;
  241. static constexpr std::size_t NumRegisters = 0x10;
  242. explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks);
  243. ~DmntCheatVm();
  244. std::size_t GetProgramSize() const {
  245. return this->num_opcodes;
  246. }
  247. bool LoadProgram(const std::vector<CheatEntry>& cheats);
  248. void Execute(const CheatProcessMetadata& metadata);
  249. private:
  250. std::unique_ptr<Callbacks> callbacks;
  251. std::size_t num_opcodes = 0;
  252. std::size_t instruction_ptr = 0;
  253. std::size_t condition_depth = 0;
  254. bool decode_success = false;
  255. std::array<u32, MaximumProgramOpcodeCount> program{};
  256. std::array<u64, NumRegisters> registers{};
  257. std::array<u64, NumRegisters> saved_values{};
  258. std::array<std::size_t, NumRegisters> loop_tops{};
  259. bool DecodeNextOpcode(CheatVmOpcode& out);
  260. void SkipConditionalBlock();
  261. void ResetState();
  262. // For implementing the DebugLog opcode.
  263. void DebugLog(u32 log_id, u64 value);
  264. void LogOpcode(const CheatVmOpcode& opcode);
  265. static u64 GetVmInt(VmInt value, u32 bit_width);
  266. static u64 GetCheatProcessAddress(const CheatProcessMetadata& metadata,
  267. MemoryAccessType mem_type, u64 rel_address);
  268. };
  269. }; // namespace Memory