| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2008 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 22:43:11 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | // -----------------------------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2008-12-13 16:58:06 +00:00
										 |  |  | // Partial Action Replay code system implementation.
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | // Will never be able to support some AR codes - specifically those that patch the running
 | 
					
						
							|  |  |  | // Action Replay engine itself - yes they do exist!!!
 | 
					
						
							|  |  |  | // Action Replay actually is a small virtual machine with a limited number of commands.
 | 
					
						
							| 
									
										
										
										
											2010-04-11 11:16:57 +00:00
										 |  |  | // It probably is Turing complete - but what does that matter when AR codes can write
 | 
					
						
							| 
									
										
										
										
											2008-12-13 16:58:06 +00:00
										 |  |  | // actual PowerPC code...
 | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | // -----------------------------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | // -------------------------------------------------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2010-04-08 16:59:35 +00:00
										 |  |  | // Code Types:
 | 
					
						
							| 
									
										
										
										
											2013-04-19 09:21:45 -04:00
										 |  |  | // (Unconditional) Normal Codes (0): this one has subtypes inside
 | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | // (Conditional) Normal Codes (1 - 7): these just compare values and set the line skip info
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | // Zero Codes: any code with no address.  These codes are used to do special operations like memory
 | 
					
						
							|  |  |  | // copy, etc
 | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | // -------------------------------------------------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2008-12-17 04:14:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <atomic>
 | 
					
						
							|  |  |  | #include <iterator>
 | 
					
						
							| 
									
										
										
										
											2016-04-19 21:19:31 +00:00
										 |  |  | #include <mutex>
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | #include <unordered_set>
 | 
					
						
							| 
									
										
										
										
											2016-04-19 21:19:31 +00:00
										 |  |  | #include <utility>
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2015-05-08 17:28:03 -04:00
										 |  |  | #include "Common/IniFile.h"
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:29:54 -04:00
										 |  |  | #include "Common/Logging/LogManager.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-07 22:55:13 +02:00
										 |  |  | #include "Common/MsgHandler.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include "Common/StringUtil.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "Core/ARDecrypt.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include "Core/ActionReplay.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Core/ConfigManager.h"
 | 
					
						
							|  |  |  | #include "Core/Core.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-17 13:17:36 -08:00
										 |  |  | #include "Core/PowerPC/PowerPC.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 04:14:24 +00:00
										 |  |  | namespace ActionReplay | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | enum | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Zero Code Types
 | 
					
						
							|  |  |  |   ZCODE_END = 0x00, | 
					
						
							|  |  |  |   ZCODE_NORM = 0x02, | 
					
						
							|  |  |  |   ZCODE_ROW = 0x03, | 
					
						
							|  |  |  |   ZCODE_04 = 0x04, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Conditional Codes
 | 
					
						
							|  |  |  |   CONDTIONAL_EQUAL = 0x01, | 
					
						
							|  |  |  |   CONDTIONAL_NOT_EQUAL = 0x02, | 
					
						
							|  |  |  |   CONDTIONAL_LESS_THAN_SIGNED = 0x03, | 
					
						
							|  |  |  |   CONDTIONAL_GREATER_THAN_SIGNED = 0x04, | 
					
						
							|  |  |  |   CONDTIONAL_LESS_THAN_UNSIGNED = 0x05, | 
					
						
							|  |  |  |   CONDTIONAL_GREATER_THAN_UNSIGNED = 0x06, | 
					
						
							|  |  |  |   CONDTIONAL_AND = 0x07,  // bitwise AND
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Conditional Line Counts
 | 
					
						
							|  |  |  |   CONDTIONAL_ONE_LINE = 0x00, | 
					
						
							|  |  |  |   CONDTIONAL_TWO_LINES = 0x01, | 
					
						
							|  |  |  |   CONDTIONAL_ALL_LINES_UNTIL = 0x02, | 
					
						
							|  |  |  |   CONDTIONAL_ALL_LINES = 0x03, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Data Types
 | 
					
						
							|  |  |  |   DATATYPE_8BIT = 0x00, | 
					
						
							|  |  |  |   DATATYPE_16BIT = 0x01, | 
					
						
							|  |  |  |   DATATYPE_32BIT = 0x02, | 
					
						
							|  |  |  |   DATATYPE_32BIT_FLOAT = 0x03, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Normal Code 0 Subtypes
 | 
					
						
							|  |  |  |   SUB_RAM_WRITE = 0x00, | 
					
						
							|  |  |  |   SUB_WRITE_POINTER = 0x01, | 
					
						
							|  |  |  |   SUB_ADD_CODE = 0x02, | 
					
						
							|  |  |  |   SUB_MASTER_CODE = 0x03, | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2008-12-17 04:14:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | // General lock. Protects codes list and internal log.
 | 
					
						
							|  |  |  | static std::mutex s_lock; | 
					
						
							|  |  |  | static std::vector<ARCode> s_active_codes; | 
					
						
							|  |  |  | static std::vector<std::string> s_internal_log; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static std::atomic<bool> s_use_internal_log{false}; | 
					
						
							| 
									
										
										
										
											2010-07-19 02:08:34 +00:00
										 |  |  | // pointer to the code currently being run, (used by log messages that include the code name)
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | static const ARCode* s_current_code = nullptr; | 
					
						
							|  |  |  | static bool s_disable_logging = false; | 
					
						
							| 
									
										
										
										
											2016-04-19 21:19:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-19 02:08:34 +00:00
										 |  |  | struct ARAddr | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-01-04 12:45:40 +01:00
										 |  |  |   union | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     u32 address; | 
					
						
							|  |  |  |     struct | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       u32 gcaddr : 25; | 
					
						
							|  |  |  |       u32 size : 2; | 
					
						
							|  |  |  |       u32 type : 3; | 
					
						
							|  |  |  |       u32 subtype : 2; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ARAddr(const u32 addr) : address(addr) {} | 
					
						
							|  |  |  |   u32 GCAddress() const { return gcaddr | 0x80000000; } | 
					
						
							|  |  |  |   operator u32() const { return address; } | 
					
						
							| 
									
										
										
										
											2010-07-19 02:08:34 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | // ----------------------
 | 
					
						
							|  |  |  | // AR Remote Functions
 | 
					
						
							| 
									
										
										
										
											2016-04-19 21:19:31 +00:00
										 |  |  | void ApplyCodes(const std::vector<ARCode>& codes) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (!SConfig::GetInstance().bEnableCheats) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::lock_guard<std::mutex> guard(s_lock); | 
					
						
							|  |  |  |   s_disable_logging = false; | 
					
						
							|  |  |  |   s_active_codes.clear(); | 
					
						
							|  |  |  |   std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes), | 
					
						
							|  |  |  |                [](const ARCode& code) { return code.active; }); | 
					
						
							|  |  |  |   s_active_codes.shrink_to_fit(); | 
					
						
							| 
									
										
										
										
											2016-04-19 21:19:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | void AddCode(ARCode code) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (!SConfig::GetInstance().bEnableCheats) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (code.active) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     std::lock_guard<std::mutex> guard(s_lock); | 
					
						
							|  |  |  |     s_disable_logging = false; | 
					
						
							|  |  |  |     s_active_codes.emplace_back(std::move(code)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-04-19 21:19:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | void LoadAndApplyCodes(const IniFile& global_ini, const IniFile& local_ini) | 
					
						
							| 
									
										
										
										
											2016-04-19 21:19:31 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ApplyCodes(LoadCodes(global_ini, local_ini)); | 
					
						
							| 
									
										
										
										
											2016-04-19 21:19:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Parses the Action Replay section of a game ini file.
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_ini) | 
					
						
							| 
									
										
										
										
											2016-04-19 21:19:31 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::vector<ARCode> codes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::unordered_set<std::string> enabled_names; | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     std::vector<std::string> enabled_lines; | 
					
						
							|  |  |  |     local_ini.GetLines("ActionReplay_Enabled", &enabled_lines); | 
					
						
							|  |  |  |     for (const std::string& line : enabled_lines) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (line.size() != 0 && line[0] == '$') | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         std::string name = line.substr(1, line.size() - 1); | 
					
						
							|  |  |  |         enabled_names.insert(name); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const IniFile* inis[2] = {&global_ini, &local_ini}; | 
					
						
							|  |  |  |   for (const IniFile* ini : inis) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     std::vector<std::string> lines; | 
					
						
							|  |  |  |     std::vector<std::string> encrypted_lines; | 
					
						
							|  |  |  |     ARCode current_code; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ini->GetLines("ActionReplay", &lines); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (const std::string& line : lines) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (line.empty()) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       std::vector<std::string> pieces; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Check if the line is a name of the code
 | 
					
						
							|  |  |  |       if (line[0] == '$') | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         if (current_code.ops.size()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           codes.push_back(current_code); | 
					
						
							|  |  |  |           current_code.ops.clear(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (encrypted_lines.size()) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2016-07-23 01:05:04 +00:00
										 |  |  |           DecryptARCode(encrypted_lines, ¤t_code.ops); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |           codes.push_back(current_code); | 
					
						
							|  |  |  |           current_code.ops.clear(); | 
					
						
							|  |  |  |           encrypted_lines.clear(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         current_code.name = line.substr(1, line.size() - 1); | 
					
						
							|  |  |  |         current_code.active = enabled_names.find(current_code.name) != enabled_names.end(); | 
					
						
							|  |  |  |         current_code.user_defined = (ini == &local_ini); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         SplitString(line, ' ', pieces); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Check if the AR code is decrypted
 | 
					
						
							|  |  |  |         if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           AREntry op; | 
					
						
							|  |  |  |           bool success_addr = TryParse(std::string("0x") + pieces[0], &op.cmd_addr); | 
					
						
							|  |  |  |           bool success_val = TryParse(std::string("0x") + pieces[1], &op.value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (success_addr && success_val) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             current_code.ops.push_back(op); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             PanicAlertT("Action Replay Error: invalid AR code line: %s", line.c_str()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!success_addr) | 
					
						
							|  |  |  |               PanicAlertT("The address is invalid"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!success_val) | 
					
						
							|  |  |  |               PanicAlertT("The value is invalid"); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           SplitString(line, '-', pieces); | 
					
						
							|  |  |  |           if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && | 
					
						
							|  |  |  |               pieces[2].size() == 5) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             // Encrypted AR code
 | 
					
						
							|  |  |  |             // Decryption is done in "blocks", so we must push blocks into a vector,
 | 
					
						
							|  |  |  |             // then send to decrypt when a new block is encountered, or if it's the last block.
 | 
					
						
							|  |  |  |             encrypted_lines.emplace_back(pieces[0] + pieces[1] + pieces[2]); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Handle the last code correctly.
 | 
					
						
							|  |  |  |     if (current_code.ops.size()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       codes.push_back(current_code); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (encrypted_lines.size()) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-07-23 01:05:04 +00:00
										 |  |  |       DecryptARCode(encrypted_lines, ¤t_code.ops); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       codes.push_back(current_code); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return codes; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | void SaveCodes(IniFile* local_ini, const std::vector<ARCode>& codes) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::vector<std::string> lines; | 
					
						
							|  |  |  |   std::vector<std::string> enabled_lines; | 
					
						
							|  |  |  |   for (const ActionReplay::ARCode& code : codes) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (code.active) | 
					
						
							|  |  |  |       enabled_lines.emplace_back("$" + code.name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (code.user_defined) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       lines.emplace_back("$" + code.name); | 
					
						
							|  |  |  |       for (const ActionReplay::AREntry& op : code.ops) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         lines.emplace_back(StringFromFormat("%08X %08X", op.cmd_addr, op.value)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   local_ini->SetLines("ActionReplay_Enabled", enabled_lines); | 
					
						
							|  |  |  |   local_ini->SetLines("ActionReplay", lines); | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | static void LogInfo(const char* format, ...) | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (s_disable_logging) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   bool use_internal_log = s_use_internal_log.load(std::memory_order_relaxed); | 
					
						
							|  |  |  |   if (LogManager::GetMaxLevel() < LogTypes::LINFO && !use_internal_log) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   va_list args; | 
					
						
							|  |  |  |   va_start(args, format); | 
					
						
							|  |  |  |   std::string text = StringFromFormatV(format, args); | 
					
						
							|  |  |  |   va_end(args); | 
					
						
							|  |  |  |   INFO_LOG(ACTIONREPLAY, "%s", text.c_str()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (use_internal_log) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     text += '\n'; | 
					
						
							|  |  |  |     s_internal_log.emplace_back(std::move(text)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | void EnableSelfLogging(bool enable) | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_use_internal_log.store(enable, std::memory_order_relaxed); | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | std::vector<std::string> GetSelfLog() | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::lock_guard<std::mutex> guard(s_lock); | 
					
						
							|  |  |  |   return s_internal_log; | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | void ClearSelfLog() | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::lock_guard<std::mutex> guard(s_lock); | 
					
						
							|  |  |  |   s_internal_log.clear(); | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool IsSelfLogging() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return s_use_internal_log.load(std::memory_order_relaxed); | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ----------------------
 | 
					
						
							|  |  |  | // Code Functions
 | 
					
						
							| 
									
										
										
										
											2014-08-09 00:18:59 -04:00
										 |  |  | static bool Subtype_RamWriteAndFill(const ARAddr& addr, const u32 data) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const u32 new_addr = addr.GCAddress(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LogInfo("Hardware Address: %08x", new_addr); | 
					
						
							|  |  |  |   LogInfo("Size: %08x", addr.size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (addr.size) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case DATATYPE_8BIT: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     LogInfo("8-bit Write"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     u32 repeat = data >> 8; | 
					
						
							|  |  |  |     for (u32 i = 0; i <= repeat; ++i) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       PowerPC::HostWrite_U8(data & 0xFF, new_addr + i); | 
					
						
							|  |  |  |       LogInfo("Wrote %08x to address %08x", data & 0xFF, new_addr + i); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_16BIT: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     LogInfo("16-bit Write"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     u32 repeat = data >> 16; | 
					
						
							|  |  |  |     for (u32 i = 0; i <= repeat; ++i) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       PowerPC::HostWrite_U16(data & 0xFFFF, new_addr + i * 2); | 
					
						
							|  |  |  |       LogInfo("Wrote %08x to address %08x", data & 0xFFFF, new_addr + i * 2); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_32BIT_FLOAT: | 
					
						
							|  |  |  |   case DATATYPE_32BIT:  // Dword write
 | 
					
						
							|  |  |  |     LogInfo("32-bit Write"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     PowerPC::HostWrite_U32(data, new_addr); | 
					
						
							|  |  |  |     LogInfo("Wrote %08x to address %08x", data, new_addr); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     LogInfo("Bad Size"); | 
					
						
							|  |  |  |     PanicAlertT("Action Replay Error: Invalid size " | 
					
						
							|  |  |  |                 "(%08x : address = %08x) in Ram Write And Fill (%s)", | 
					
						
							|  |  |  |                 addr.size, addr.gcaddr, s_current_code->name.c_str()); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-09 00:18:59 -04:00
										 |  |  | static bool Subtype_WriteToPointer(const ARAddr& addr, const u32 data) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const u32 new_addr = addr.GCAddress(); | 
					
						
							|  |  |  |   const u32 ptr = PowerPC::HostRead_U32(new_addr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LogInfo("Hardware Address: %08x", new_addr); | 
					
						
							|  |  |  |   LogInfo("Size: %08x", addr.size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (addr.size) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case DATATYPE_8BIT: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     LogInfo("Write 8-bit to pointer"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     const u8 thebyte = data & 0xFF; | 
					
						
							|  |  |  |     const u32 offset = data >> 8; | 
					
						
							|  |  |  |     LogInfo("Pointer: %08x", ptr); | 
					
						
							|  |  |  |     LogInfo("Byte: %08x", thebyte); | 
					
						
							|  |  |  |     LogInfo("Offset: %08x", offset); | 
					
						
							|  |  |  |     PowerPC::HostWrite_U8(thebyte, ptr + offset); | 
					
						
							|  |  |  |     LogInfo("Wrote %08x to address %08x", thebyte, ptr + offset); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_16BIT: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     LogInfo("Write 16-bit to pointer"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     const u16 theshort = data & 0xFFFF; | 
					
						
							|  |  |  |     const u32 offset = (data >> 16) << 1; | 
					
						
							|  |  |  |     LogInfo("Pointer: %08x", ptr); | 
					
						
							|  |  |  |     LogInfo("Byte: %08x", theshort); | 
					
						
							|  |  |  |     LogInfo("Offset: %08x", offset); | 
					
						
							|  |  |  |     PowerPC::HostWrite_U16(theshort, ptr + offset); | 
					
						
							|  |  |  |     LogInfo("Wrote %08x to address %08x", theshort, ptr + offset); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_32BIT_FLOAT: | 
					
						
							|  |  |  |   case DATATYPE_32BIT: | 
					
						
							|  |  |  |     LogInfo("Write 32-bit to pointer"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     PowerPC::HostWrite_U32(data, ptr); | 
					
						
							|  |  |  |     LogInfo("Wrote %08x to address %08x", data, ptr); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     LogInfo("Bad Size"); | 
					
						
							|  |  |  |     PanicAlertT("Action Replay Error: Invalid size " | 
					
						
							|  |  |  |                 "(%08x : address = %08x) in Write To Pointer (%s)", | 
					
						
							|  |  |  |                 addr.size, addr.gcaddr, s_current_code->name.c_str()); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-09 00:18:59 -04:00
										 |  |  | static bool Subtype_AddCode(const ARAddr& addr, const u32 data) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Used to increment/decrement a value in memory
 | 
					
						
							|  |  |  |   const u32 new_addr = addr.GCAddress(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LogInfo("Hardware Address: %08x", new_addr); | 
					
						
							|  |  |  |   LogInfo("Size: %08x", addr.size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (addr.size) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case DATATYPE_8BIT: | 
					
						
							|  |  |  |     LogInfo("8-bit Add"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     PowerPC::HostWrite_U8(PowerPC::HostRead_U8(new_addr) + data, new_addr); | 
					
						
							|  |  |  |     LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(new_addr) + (data & 0xFF), new_addr); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_16BIT: | 
					
						
							|  |  |  |     LogInfo("16-bit Add"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     PowerPC::HostWrite_U16(PowerPC::HostRead_U16(new_addr) + data, new_addr); | 
					
						
							|  |  |  |     LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U16(new_addr) + (data & 0xFFFF), | 
					
						
							|  |  |  |             new_addr); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_32BIT: | 
					
						
							|  |  |  |     LogInfo("32-bit Add"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     PowerPC::HostWrite_U32(PowerPC::HostRead_U32(new_addr) + data, new_addr); | 
					
						
							|  |  |  |     LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U32(new_addr) + data, new_addr); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_32BIT_FLOAT: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     LogInfo("32-bit floating Add"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const u32 read = PowerPC::HostRead_U32(new_addr); | 
					
						
							|  |  |  |     const float read_float = reinterpret_cast<const float&>(read); | 
					
						
							|  |  |  |     // data contains an (unsigned?) integer value
 | 
					
						
							|  |  |  |     const float fread = read_float + static_cast<float>(data); | 
					
						
							|  |  |  |     const u32 newval = reinterpret_cast<const u32&>(fread); | 
					
						
							|  |  |  |     PowerPC::HostWrite_U32(newval, new_addr); | 
					
						
							|  |  |  |     LogInfo("Old Value %08x", read); | 
					
						
							|  |  |  |     LogInfo("Increment %08x", data); | 
					
						
							|  |  |  |     LogInfo("New value %08x", newval); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     LogInfo("Bad Size"); | 
					
						
							|  |  |  |     PanicAlertT("Action Replay Error: Invalid size " | 
					
						
							|  |  |  |                 "(%08x : address = %08x) in Add Code (%s)", | 
					
						
							|  |  |  |                 addr.size, addr.gcaddr, s_current_code->name.c_str()); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-09 00:18:59 -04:00
										 |  |  | static bool Subtype_MasterCodeAndWriteToCCXXXXXX(const ARAddr& addr, const u32 data) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // code not yet implemented - TODO
 | 
					
						
							|  |  |  |   // u32 new_addr = (addr & 0x01FFFFFF) | 0x80000000;
 | 
					
						
							|  |  |  |   // u8  mcode_type = (data & 0xFF0000) >> 16;
 | 
					
						
							|  |  |  |   // u8  mcode_count = (data & 0xFF00) >> 8;
 | 
					
						
							|  |  |  |   // u8  mcode_number = data & 0xFF;
 | 
					
						
							|  |  |  |   PanicAlertT("Action Replay Error: Master Code and Write To CCXXXXXX not implemented (%s)\n" | 
					
						
							|  |  |  |               "Master codes are not needed. Do not use master codes.", | 
					
						
							|  |  |  |               s_current_code->name.c_str()); | 
					
						
							|  |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | // This needs more testing
 | 
					
						
							|  |  |  | static bool ZeroCode_FillAndSlide(const u32 val_last, const ARAddr& addr, const u32 data) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const u32 new_addr = ARAddr(val_last).GCAddress(); | 
					
						
							|  |  |  |   const u8 size = ARAddr(val_last).size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const s16 addr_incr = static_cast<s16>(data & 0xFFFF); | 
					
						
							|  |  |  |   const s8 val_incr = static_cast<s8>(data >> 24); | 
					
						
							|  |  |  |   const u8 write_num = static_cast<u8>((data & 0xFF0000) >> 16); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   u32 val = addr; | 
					
						
							|  |  |  |   u32 curr_addr = new_addr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LogInfo("Current Hardware Address: %08x", new_addr); | 
					
						
							|  |  |  |   LogInfo("Size: %08x", addr.size); | 
					
						
							|  |  |  |   LogInfo("Write Num: %08x", write_num); | 
					
						
							|  |  |  |   LogInfo("Address Increment: %i", addr_incr); | 
					
						
							|  |  |  |   LogInfo("Value Increment: %i", val_incr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (size) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case DATATYPE_8BIT: | 
					
						
							|  |  |  |     LogInfo("8-bit Write"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     for (int i = 0; i < write_num; ++i) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       PowerPC::HostWrite_U8(val & 0xFF, curr_addr); | 
					
						
							|  |  |  |       curr_addr += addr_incr; | 
					
						
							|  |  |  |       val += val_incr; | 
					
						
							|  |  |  |       LogInfo("Write %08x to address %08x", val & 0xFF, curr_addr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       LogInfo("Value Update: %08x", val); | 
					
						
							|  |  |  |       LogInfo("Current Hardware Address Update: %08x", curr_addr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_16BIT: | 
					
						
							|  |  |  |     LogInfo("16-bit Write"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     for (int i = 0; i < write_num; ++i) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       PowerPC::HostWrite_U16(val & 0xFFFF, curr_addr); | 
					
						
							|  |  |  |       LogInfo("Write %08x to address %08x", val & 0xFFFF, curr_addr); | 
					
						
							|  |  |  |       curr_addr += addr_incr * 2; | 
					
						
							|  |  |  |       val += val_incr; | 
					
						
							|  |  |  |       LogInfo("Value Update: %08x", val); | 
					
						
							|  |  |  |       LogInfo("Current Hardware Address Update: %08x", curr_addr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_32BIT: | 
					
						
							|  |  |  |     LogInfo("32-bit Write"); | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     for (int i = 0; i < write_num; ++i) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       PowerPC::HostWrite_U32(val, curr_addr); | 
					
						
							|  |  |  |       LogInfo("Write %08x to address %08x", val, curr_addr); | 
					
						
							|  |  |  |       curr_addr += addr_incr * 4; | 
					
						
							|  |  |  |       val += val_incr; | 
					
						
							|  |  |  |       LogInfo("Value Update: %08x", val); | 
					
						
							|  |  |  |       LogInfo("Current Hardware Address Update: %08x", curr_addr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     LogInfo("--------"); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     LogInfo("Bad Size"); | 
					
						
							|  |  |  |     PanicAlertT("Action Replay Error: Invalid size (%08x : address = %08x) in Fill and Slide (%s)", | 
					
						
							|  |  |  |                 size, new_addr, s_current_code->name.c_str()); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-08 16:59:35 +00:00
										 |  |  | // Looks like this is new?? - untested
 | 
					
						
							| 
									
										
										
										
											2014-08-09 00:18:59 -04:00
										 |  |  | static bool ZeroCode_MemoryCopy(const u32 val_last, const ARAddr& addr, const u32 data) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const u32 addr_dest = val_last | 0x06000000; | 
					
						
							|  |  |  |   const u32 addr_src = addr.GCAddress(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const u8 num_bytes = data & 0x7FFF; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LogInfo("Dest Address: %08x", addr_dest); | 
					
						
							|  |  |  |   LogInfo("Src Address: %08x", addr_src); | 
					
						
							|  |  |  |   LogInfo("Size: %08x", num_bytes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ((data & ~0x7FFF) == 0x0000) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if ((data >> 24) != 0x0) | 
					
						
							|  |  |  |     {  // Memory Copy With Pointers Support
 | 
					
						
							|  |  |  |       LogInfo("Memory Copy With Pointers Support"); | 
					
						
							|  |  |  |       LogInfo("--------"); | 
					
						
							|  |  |  |       for (int i = 0; i < 138; ++i) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i); | 
					
						
							|  |  |  |         LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(addr_src + i), addr_dest + i); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       LogInfo("--------"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     {  // Memory Copy Without Pointer Support
 | 
					
						
							|  |  |  |       LogInfo("Memory Copy Without Pointers Support"); | 
					
						
							|  |  |  |       LogInfo("--------"); | 
					
						
							|  |  |  |       for (int i = 0; i < num_bytes; ++i) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         PowerPC::HostWrite_U8(PowerPC::HostRead_U8(addr_src + i), addr_dest + i); | 
					
						
							|  |  |  |         LogInfo("Wrote %08x to address %08x", PowerPC::HostRead_U8(addr_src + i), addr_dest + i); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       LogInfo("--------"); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     LogInfo("Bad Value"); | 
					
						
							|  |  |  |     PanicAlertT("Action Replay Error: Invalid value (%08x) in Memory Copy (%s)", (data & ~0x7FFF), | 
					
						
							|  |  |  |                 s_current_code->name.c_str()); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-09 00:18:59 -04:00
										 |  |  | static bool NormalCode(const ARAddr& addr, const u32 data) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   switch (addr.subtype) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case SUB_RAM_WRITE:  // Ram write (and fill)
 | 
					
						
							|  |  |  |     LogInfo("Doing Ram Write And Fill"); | 
					
						
							|  |  |  |     if (!Subtype_RamWriteAndFill(addr, data)) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case SUB_WRITE_POINTER:  // Write to pointer
 | 
					
						
							|  |  |  |     LogInfo("Doing Write To Pointer"); | 
					
						
							|  |  |  |     if (!Subtype_WriteToPointer(addr, data)) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case SUB_ADD_CODE:  // Increment Value
 | 
					
						
							|  |  |  |     LogInfo("Doing Add Code"); | 
					
						
							|  |  |  |     if (!Subtype_AddCode(addr, data)) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case SUB_MASTER_CODE:  // Master Code & Write to CCXXXXXX
 | 
					
						
							|  |  |  |     LogInfo("Doing Master Code And Write to CCXXXXXX (ncode not supported)"); | 
					
						
							|  |  |  |     if (!Subtype_MasterCodeAndWriteToCCXXXXXX(addr, data)) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     LogInfo("Bad Subtype"); | 
					
						
							|  |  |  |     PanicAlertT("Action Replay: Normal Code 0: Invalid Subtype %08x (%s)", addr.subtype, | 
					
						
							|  |  |  |                 s_current_code->name.c_str()); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-19 02:08:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-09 00:18:59 -04:00
										 |  |  | static bool CompareValues(const u32 val1, const u32 val2, const int type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   switch (type) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case CONDTIONAL_EQUAL: | 
					
						
							|  |  |  |     LogInfo("Type 1: If Equal"); | 
					
						
							|  |  |  |     return val1 == val2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case CONDTIONAL_NOT_EQUAL: | 
					
						
							|  |  |  |     LogInfo("Type 2: If Not Equal"); | 
					
						
							|  |  |  |     return val1 != val2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case CONDTIONAL_LESS_THAN_SIGNED: | 
					
						
							|  |  |  |     LogInfo("Type 3: If Less Than (Signed)"); | 
					
						
							|  |  |  |     return static_cast<s32>(val1) < static_cast<s32>(val2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case CONDTIONAL_GREATER_THAN_SIGNED: | 
					
						
							|  |  |  |     LogInfo("Type 4: If Greater Than (Signed)"); | 
					
						
							|  |  |  |     return static_cast<s32>(val1) > static_cast<s32>(val2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case CONDTIONAL_LESS_THAN_UNSIGNED: | 
					
						
							|  |  |  |     LogInfo("Type 5: If Less Than (Unsigned)"); | 
					
						
							|  |  |  |     return val1 < val2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case CONDTIONAL_GREATER_THAN_UNSIGNED: | 
					
						
							|  |  |  |     LogInfo("Type 6: If Greater Than (Unsigned)"); | 
					
						
							|  |  |  |     return val1 > val2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case CONDTIONAL_AND: | 
					
						
							|  |  |  |     LogInfo("Type 7: If And"); | 
					
						
							|  |  |  |     return !!(val1 & val2);  // bitwise AND
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     LogInfo("Unknown Compare type"); | 
					
						
							|  |  |  |     PanicAlertT("Action Replay: Invalid Normal Code Type %08x (%s)", type, | 
					
						
							|  |  |  |                 s_current_code->name.c_str()); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-08-09 00:18:59 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool ConditionalCode(const ARAddr& addr, const u32 data, int* const pSkipCount) | 
					
						
							| 
									
										
										
										
											2008-12-08 05:30:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const u32 new_addr = addr.GCAddress(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LogInfo("Size: %08x", addr.size); | 
					
						
							|  |  |  |   LogInfo("Hardware Address: %08x", new_addr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool result = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (addr.size) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case DATATYPE_8BIT: | 
					
						
							|  |  |  |     result = CompareValues(PowerPC::HostRead_U8(new_addr), (data & 0xFF), addr.type); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_16BIT: | 
					
						
							|  |  |  |     result = CompareValues(PowerPC::HostRead_U16(new_addr), (data & 0xFFFF), addr.type); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case DATATYPE_32BIT_FLOAT: | 
					
						
							|  |  |  |   case DATATYPE_32BIT: | 
					
						
							|  |  |  |     result = CompareValues(PowerPC::HostRead_U32(new_addr), data, addr.type); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     LogInfo("Bad Size"); | 
					
						
							|  |  |  |     PanicAlertT("Action Replay: Conditional Code: Invalid Size %08x (%s)", addr.size, | 
					
						
							|  |  |  |                 s_current_code->name.c_str()); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // if the comparison failed we need to skip some lines
 | 
					
						
							|  |  |  |   if (false == result) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     switch (addr.subtype) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case CONDTIONAL_ONE_LINE: | 
					
						
							|  |  |  |     case CONDTIONAL_TWO_LINES: | 
					
						
							|  |  |  |       *pSkipCount = addr.subtype + 1;  // Skip 1 or 2 lines
 | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Skip all lines,
 | 
					
						
							|  |  |  |     // Skip lines until a "00000000 40000000" line is reached
 | 
					
						
							|  |  |  |     case CONDTIONAL_ALL_LINES: | 
					
						
							|  |  |  |     case CONDTIONAL_ALL_LINES_UNTIL: | 
					
						
							|  |  |  |       *pSkipCount = -static_cast<int>(addr.subtype); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       LogInfo("Bad Subtype"); | 
					
						
							|  |  |  |       PanicAlertT("Action Replay: Normal Code %i: Invalid subtype %08x (%s)", 1, addr.subtype, | 
					
						
							|  |  |  |                   s_current_code->name.c_str()); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2008-12-20 19:51:16 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-19 02:08:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | // NOTE: Lock needed to give mutual exclusion to s_current_code and LogInfo
 | 
					
						
							|  |  |  | static bool RunCodeLocked(const ARCode& arcode) | 
					
						
							| 
									
										
										
										
											2014-08-09 00:18:59 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // The mechanism is different than what the real AR uses, so there may be compatibility problems.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool do_fill_and_slide = false; | 
					
						
							|  |  |  |   bool do_memory_copy = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // used for conditional codes
 | 
					
						
							|  |  |  |   int skip_count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   u32 val_last = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   s_current_code = &arcode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LogInfo("Code Name: %s", arcode.name.c_str()); | 
					
						
							|  |  |  |   LogInfo("Number of codes: %zu", arcode.ops.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (const AREntry& entry : arcode.ops) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     const ARAddr addr(entry.cmd_addr); | 
					
						
							|  |  |  |     const u32 data = entry.value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // after a conditional code, skip lines if needed
 | 
					
						
							|  |  |  |     if (skip_count) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (skip_count > 0)  // skip x lines
 | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         LogInfo("Line skipped"); | 
					
						
							|  |  |  |         --skip_count; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else if (-CONDTIONAL_ALL_LINES == skip_count) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // skip all lines
 | 
					
						
							|  |  |  |         LogInfo("All Lines skipped"); | 
					
						
							|  |  |  |         return true;  // don't need to iterate through the rest of the ops
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else if (-CONDTIONAL_ALL_LINES_UNTIL == skip_count) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // skip until a "00000000 40000000" line is reached
 | 
					
						
							|  |  |  |         LogInfo("Line skipped"); | 
					
						
							|  |  |  |         if (addr == 0 && 0x40000000 == data)  // check for an endif line
 | 
					
						
							|  |  |  |           skip_count = 0; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     LogInfo("--- Running Code: %08x %08x ---", addr.address, data); | 
					
						
							|  |  |  |     // LogInfo("Command: %08x", cmd);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Do Fill & Slide
 | 
					
						
							|  |  |  |     if (do_fill_and_slide) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       do_fill_and_slide = false; | 
					
						
							|  |  |  |       LogInfo("Doing Fill And Slide"); | 
					
						
							|  |  |  |       if (false == ZeroCode_FillAndSlide(val_last, addr, data)) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Memory Copy
 | 
					
						
							|  |  |  |     if (do_memory_copy) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       do_memory_copy = false; | 
					
						
							|  |  |  |       LogInfo("Doing Memory Copy"); | 
					
						
							|  |  |  |       if (false == ZeroCode_MemoryCopy(val_last, addr, data)) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // ActionReplay program self modification codes
 | 
					
						
							|  |  |  |     if (addr >= 0x00002000 && addr < 0x00003000) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       LogInfo( | 
					
						
							|  |  |  |           "This action replay simulator does not support codes that modify Action Replay itself."); | 
					
						
							|  |  |  |       PanicAlertT( | 
					
						
							|  |  |  |           "This action replay simulator does not support codes that modify Action Replay itself."); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // skip these weird init lines
 | 
					
						
							|  |  |  |     // TODO: Where are the "weird init lines"?
 | 
					
						
							|  |  |  |     // if (iter == code.ops.begin() && cmd == 1)
 | 
					
						
							|  |  |  |     // continue;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Zero codes
 | 
					
						
							|  |  |  |     if (0x0 == addr)  // Check if the code is a zero code
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       const u8 zcode = data >> 29; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       LogInfo("Doing Zero Code %08x", zcode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       switch (zcode) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |       case ZCODE_END:  // END OF CODES
 | 
					
						
							|  |  |  |         LogInfo("ZCode: End Of Codes"); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // TODO: the "00000000 40000000"(end if) codes fall into this case, I don't think that is
 | 
					
						
							|  |  |  |       // correct
 | 
					
						
							|  |  |  |       case ZCODE_NORM:  // Normal execution of codes
 | 
					
						
							|  |  |  |         // Todo: Set register 1BB4 to 0
 | 
					
						
							|  |  |  |         LogInfo("ZCode: Normal execution of codes, set register 1BB4 to 0 (zcode not supported)"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       case ZCODE_ROW:  // Executes all codes in the same row
 | 
					
						
							|  |  |  |         // Todo: Set register 1BB4 to 1
 | 
					
						
							|  |  |  |         LogInfo("ZCode: Executes all codes in the same row, Set register 1BB4 to 1 (zcode not " | 
					
						
							|  |  |  |                 "supported)"); | 
					
						
							|  |  |  |         PanicAlertT("Zero 3 code not supported"); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       case ZCODE_04:  // Fill & Slide or Memory Copy
 | 
					
						
							|  |  |  |         if (0x3 == ((data >> 25) & 0x03)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           LogInfo("ZCode: Memory Copy"); | 
					
						
							|  |  |  |           do_memory_copy = true; | 
					
						
							|  |  |  |           val_last = data; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           LogInfo("ZCode: Fill And Slide"); | 
					
						
							|  |  |  |           do_fill_and_slide = true; | 
					
						
							|  |  |  |           val_last = data; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         LogInfo("ZCode: Unknown"); | 
					
						
							|  |  |  |         PanicAlertT("Zero code unknown to Dolphin: %08x", zcode); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // done handling zero codes
 | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Normal codes
 | 
					
						
							|  |  |  |     LogInfo("Doing Normal Code %08x", addr.type); | 
					
						
							|  |  |  |     LogInfo("Subtype: %08x", addr.subtype); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (addr.type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0x00: | 
					
						
							|  |  |  |       if (false == NormalCode(addr, data)) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       LogInfo("This Normal Code is a Conditional Code"); | 
					
						
							|  |  |  |       if (false == ConditionalCode(addr, data, &skip_count)) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-03-28 08:57:34 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-19 02:08:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | void RunAllActive() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (!SConfig::GetInstance().bEnableCheats) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // If the mutex is idle then acquiring it should be cheap, fast mutexes
 | 
					
						
							|  |  |  |   // are only atomic ops unless contested. It should be rare for this to
 | 
					
						
							|  |  |  |   // be contested.
 | 
					
						
							|  |  |  |   std::lock_guard<std::mutex> guard(s_lock); | 
					
						
							|  |  |  |   s_active_codes.erase(std::remove_if(s_active_codes.begin(), s_active_codes.end(), | 
					
						
							|  |  |  |                                       [](const ARCode& code) { | 
					
						
							|  |  |  |                                         bool success = RunCodeLocked(code); | 
					
						
							|  |  |  |                                         LogInfo("\n"); | 
					
						
							|  |  |  |                                         return !success; | 
					
						
							|  |  |  |                                       }), | 
					
						
							|  |  |  |                        s_active_codes.end()); | 
					
						
							|  |  |  |   s_disable_logging = true; | 
					
						
							| 
									
										
										
										
											2016-04-22 10:42:16 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | }  // namespace ActionReplay
 |