cheat_engine.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <map>
  6. #include <set>
  7. #include <vector>
  8. #include "common/bit_field.h"
  9. #include "common/common_types.h"
  10. namespace Core {
  11. class System;
  12. }
  13. namespace Core::Timing {
  14. class CoreTiming;
  15. struct EventType;
  16. } // namespace Core::Timing
  17. namespace FileSys {
  18. enum class CodeType : u32 {
  19. // 0TMR00AA AAAAAAAA YYYYYYYY YYYYYYYY
  20. // Writes a T sized value Y to the address A added to the value of register R in memory domain M
  21. WriteImmediate = 0,
  22. // 1TMC00AA AAAAAAAA YYYYYYYY YYYYYYYY
  23. // Compares the T sized value Y to the value at address A in memory domain M using the
  24. // conditional function C. If success, continues execution. If failure, jumps to the matching
  25. // EndConditional statement.
  26. Conditional = 1,
  27. // 20000000
  28. // Terminates a Conditional or ConditionalInput block.
  29. EndConditional = 2,
  30. // 300R0000 VVVVVVVV
  31. // Starts looping V times, storing the current count in register R.
  32. // Loop block is terminated with a matching 310R0000.
  33. Loop = 3,
  34. // 400R0000 VVVVVVVV VVVVVVVV
  35. // Sets the value of register R to the value V.
  36. LoadImmediate = 4,
  37. // 5TMRI0AA AAAAAAAA
  38. // Sets the value of register R to the value of width T at address A in memory domain M, with
  39. // the current value of R added to the address if I == 1.
  40. LoadIndexed = 5,
  41. // 6T0RIFG0 VVVVVVVV VVVVVVVV
  42. // Writes the value V of width T to the memory address stored in register R. Adds the value of
  43. // register G to the final calculation if F is nonzero. Increments the value of register R by T
  44. // after operation if I is nonzero.
  45. StoreIndexed = 6,
  46. // 7T0RA000 VVVVVVVV
  47. // Performs the arithmetic operation A on the value in register R and the value V of width T,
  48. // storing the result in register R.
  49. RegisterArithmetic = 7,
  50. // 8KKKKKKK
  51. // Checks to see if any of the buttons defined by the bitmask K are pressed. If any are,
  52. // execution continues. If none are, execution skips to the next EndConditional command.
  53. ConditionalInput = 8,
  54. };
  55. enum class MemoryType : u32 {
  56. // Addressed relative to start of main NSO
  57. MainNSO = 0,
  58. // Addressed relative to start of heap
  59. Heap = 1,
  60. };
  61. enum class ArithmeticOp : u32 {
  62. Add = 0,
  63. Sub = 1,
  64. Mult = 2,
  65. LShift = 3,
  66. RShift = 4,
  67. };
  68. enum class ComparisonOp : u32 {
  69. GreaterThan = 1,
  70. GreaterThanEqual = 2,
  71. LessThan = 3,
  72. LessThanEqual = 4,
  73. Equal = 5,
  74. Inequal = 6,
  75. };
  76. union Cheat {
  77. std::array<u8, 16> raw;
  78. BitField<4, 4, CodeType> type;
  79. BitField<0, 4, u32> width; // Can be 1, 2, 4, or 8. Measured in bytes.
  80. BitField<0, 4, u32> end_of_loop;
  81. BitField<12, 4, MemoryType> memory_type;
  82. BitField<8, 4, u32> register_3;
  83. BitField<8, 4, ComparisonOp> comparison_op;
  84. BitField<20, 4, u32> load_from_register;
  85. BitField<20, 4, u32> increment_register;
  86. BitField<20, 4, ArithmeticOp> arithmetic_op;
  87. BitField<16, 4, u32> add_additional_register;
  88. BitField<28, 4, u32> register_6;
  89. u64 Address() const;
  90. u64 ValueWidth(u64 offset) const;
  91. u64 Value(u64 offset, u64 width) const;
  92. u32 KeypadValue() const;
  93. };
  94. class CheatParser;
  95. // Represents a full collection of cheats for a game. The Execute function should be called every
  96. // interval that all cheats should be executed. Clients should not directly instantiate this class
  97. // (hence private constructor), they should instead receive an instance from CheatParser, which
  98. // guarantees the list is always in an acceptable state.
  99. class CheatList {
  100. public:
  101. friend class CheatParser;
  102. using Block = std::vector<Cheat>;
  103. using ProgramSegment = std::vector<std::pair<std::string, Block>>;
  104. // (width in bytes, address, value)
  105. using MemoryWriter = void (*)(u32, VAddr, u64);
  106. // (width in bytes, address) -> value
  107. using MemoryReader = u64 (*)(u32, VAddr);
  108. void SetMemoryParameters(VAddr main_begin, VAddr heap_begin, VAddr main_end, VAddr heap_end,
  109. MemoryWriter writer, MemoryReader reader);
  110. void Execute();
  111. private:
  112. CheatList(const Core::System& system_, ProgramSegment master, ProgramSegment standard);
  113. void ProcessBlockPairs(const Block& block);
  114. void ExecuteSingleCheat(const Cheat& cheat);
  115. void ExecuteBlock(const Block& block);
  116. bool EvaluateConditional(const Cheat& cheat) const;
  117. // Individual cheat operations
  118. void WriteImmediate(const Cheat& cheat);
  119. void BeginConditional(const Cheat& cheat);
  120. void EndConditional(const Cheat& cheat);
  121. void Loop(const Cheat& cheat);
  122. void LoadImmediate(const Cheat& cheat);
  123. void LoadIndexed(const Cheat& cheat);
  124. void StoreIndexed(const Cheat& cheat);
  125. void RegisterArithmetic(const Cheat& cheat);
  126. void BeginConditionalInput(const Cheat& cheat);
  127. VAddr SanitizeAddress(VAddr in) const;
  128. // Master Codes are defined as codes that cannot be disabled and are run prior to all
  129. // others.
  130. ProgramSegment master_list;
  131. // All other codes
  132. ProgramSegment standard_list;
  133. bool in_standard = false;
  134. // 16 (0x0-0xF) scratch registers that can be used by cheats
  135. std::array<u64, 16> scratch{};
  136. MemoryWriter writer = nullptr;
  137. MemoryReader reader = nullptr;
  138. u64 main_region_begin{};
  139. u64 heap_region_begin{};
  140. u64 main_region_end{};
  141. u64 heap_region_end{};
  142. u64 current_block{};
  143. // The current index of the cheat within the current Block
  144. u64 current_index{};
  145. // The 'stack' of the program. When a conditional or loop statement is encountered, its index is
  146. // pushed onto this queue. When a end block is encountered, the condition is checked.
  147. std::map<u64, u64> block_pairs;
  148. std::set<u64> encountered_loops;
  149. const Core::System* system;
  150. };
  151. // Intermediary class that parses a text file or other disk format for storing cheats into a
  152. // CheatList object, that can be used for execution.
  153. class CheatParser {
  154. public:
  155. virtual ~CheatParser();
  156. virtual CheatList Parse(const Core::System& system, const std::vector<u8>& data) const = 0;
  157. protected:
  158. CheatList MakeCheatList(const Core::System& system_, CheatList::ProgramSegment master,
  159. CheatList::ProgramSegment standard) const;
  160. };
  161. // CheatParser implementation that parses text files
  162. class TextCheatParser final : public CheatParser {
  163. public:
  164. ~TextCheatParser() override;
  165. CheatList Parse(const Core::System& system, const std::vector<u8>& data) const override;
  166. private:
  167. std::array<u8, 16> ParseSingleLineCheat(const std::string& line) const;
  168. };
  169. // Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming
  170. class CheatEngine final {
  171. public:
  172. CheatEngine(Core::System& system_, std::vector<CheatList> cheats_, const std::string& build_id,
  173. VAddr code_region_start, VAddr code_region_end);
  174. ~CheatEngine();
  175. private:
  176. void FrameCallback(u64 userdata, s64 cycles_late);
  177. std::vector<CheatList> cheats;
  178. Core::Timing::EventType* event;
  179. Core::Timing::CoreTiming& core_timing;
  180. };
  181. } // namespace FileSys