diff options
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Tamper/InstructionHelper.cs')
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Tamper/InstructionHelper.cs | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/HOS/Tamper/InstructionHelper.cs b/src/Ryujinx.HLE/HOS/Tamper/InstructionHelper.cs new file mode 100644 index 00000000..e85d99c7 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Tamper/InstructionHelper.cs @@ -0,0 +1,133 @@ +using Ryujinx.HLE.Exceptions; +using Ryujinx.HLE.HOS.Tamper.Conditions; +using Ryujinx.HLE.HOS.Tamper.Operations; +using System; +using System.Globalization; + +namespace Ryujinx.HLE.HOS.Tamper +{ + class InstructionHelper + { + private const int CodeTypeIndex = 0; + + public static void Emit(IOperation operation, CompilationContext context) + { + context.CurrentOperations.Add(operation); + } + + public static void Emit(Type instruction, byte width, CompilationContext context, params Object[] operands) + { + Emit((IOperation)Create(instruction, width, operands), context); + } + + public static void EmitMov(byte width, CompilationContext context, IOperand destination, IOperand source) + { + Emit(typeof(OpMov<>), width, context, destination, source); + } + + public static ICondition CreateCondition(Comparison comparison, byte width, IOperand lhs, IOperand rhs) + { + ICondition Create(Type conditionType) + { + return (ICondition)InstructionHelper.Create(conditionType, width, lhs, rhs); + } + + switch (comparison) + { + case Comparison.Greater : return Create(typeof(CondGT<>)); + case Comparison.GreaterOrEqual: return Create(typeof(CondGE<>)); + case Comparison.Less : return Create(typeof(CondLT<>)); + case Comparison.LessOrEqual : return Create(typeof(CondLE<>)); + case Comparison.Equal : return Create(typeof(CondEQ<>)); + case Comparison.NotEqual : return Create(typeof(CondNE<>)); + default: + throw new TamperCompilationException($"Invalid comparison {comparison} in Atmosphere cheat"); + } + } + + public static Object Create(Type instruction, byte width, params Object[] operands) + { + Type realType; + + switch (width) + { + case 1: realType = instruction.MakeGenericType(typeof(byte)); break; + case 2: realType = instruction.MakeGenericType(typeof(ushort)); break; + case 4: realType = instruction.MakeGenericType(typeof(uint)); break; + case 8: realType = instruction.MakeGenericType(typeof(ulong)); break; + default: + throw new TamperCompilationException($"Invalid instruction width {width} in Atmosphere cheat"); + } + + return Activator.CreateInstance(realType, operands); + } + + public static ulong GetImmediate(byte[] instruction, int index, int nybbleCount) + { + ulong value = 0; + + for (int i = 0; i < nybbleCount; i++) + { + value <<= 4; + value |= instruction[index + i]; + } + + return value; + } + + public static CodeType GetCodeType(byte[] instruction) + { + int codeType = instruction[CodeTypeIndex]; + + if (codeType >= 0xC) + { + byte extension = instruction[CodeTypeIndex + 1]; + codeType = (codeType << 4) | extension; + + if (extension == 0xF) + { + extension = instruction[CodeTypeIndex + 2]; + codeType = (codeType << 4) | extension; + } + } + + return (CodeType)codeType; + } + + public static byte[] ParseRawInstruction(string rawInstruction) + { + const int wordSize = 2 * sizeof(uint); + + // Instructions are multi-word, with 32bit words. Split the raw instruction + // and parse each word into individual nybbles of bits. + + var words = rawInstruction.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); + + byte[] instruction = new byte[wordSize * words.Length]; + + if (words.Length == 0) + { + throw new TamperCompilationException("Empty instruction in Atmosphere cheat"); + } + + for (int wordIndex = 0; wordIndex < words.Length; wordIndex++) + { + string word = words[wordIndex]; + + if (word.Length != wordSize) + { + throw new TamperCompilationException($"Invalid word length for {word} in Atmosphere cheat"); + } + + for (int nybbleIndex = 0; nybbleIndex < wordSize; nybbleIndex++) + { + int index = wordIndex * wordSize + nybbleIndex; + + instruction[index] = byte.Parse(word.AsSpan(nybbleIndex, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + } + + return instruction; + } + } +} |
