InstructionHelper.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using Ryujinx.HLE.Exceptions;
  2. using Ryujinx.HLE.HOS.Tamper.Conditions;
  3. using Ryujinx.HLE.HOS.Tamper.Operations;
  4. using System;
  5. using System.Globalization;
  6. namespace Ryujinx.HLE.HOS.Tamper
  7. {
  8. class InstructionHelper
  9. {
  10. private const int CodeTypeIndex = 0;
  11. public static void Emit(IOperation operation, CompilationContext context)
  12. {
  13. context.CurrentOperations.Add(operation);
  14. }
  15. public static void Emit(Type instruction, byte width, CompilationContext context, params Object[] operands)
  16. {
  17. Emit((IOperation)Create(instruction, width, operands), context);
  18. }
  19. public static void EmitMov(byte width, CompilationContext context, IOperand destination, IOperand source)
  20. {
  21. Emit(typeof(OpMov<>), width, context, destination, source);
  22. }
  23. public static ICondition CreateCondition(Comparison comparison, byte width, IOperand lhs, IOperand rhs)
  24. {
  25. ICondition Create(Type conditionType)
  26. {
  27. return (ICondition)InstructionHelper.Create(conditionType, width, lhs, rhs);
  28. }
  29. switch (comparison)
  30. {
  31. case Comparison.Greater : return Create(typeof(CondGT<>));
  32. case Comparison.GreaterOrEqual: return Create(typeof(CondGE<>));
  33. case Comparison.Less : return Create(typeof(CondLT<>));
  34. case Comparison.LessOrEqual : return Create(typeof(CondLE<>));
  35. case Comparison.Equal : return Create(typeof(CondEQ<>));
  36. case Comparison.NotEqual : return Create(typeof(CondNE<>));
  37. default:
  38. throw new TamperCompilationException($"Invalid comparison {comparison} in Atmosphere cheat");
  39. }
  40. }
  41. public static Object Create(Type instruction, byte width, params Object[] operands)
  42. {
  43. Type realType;
  44. switch (width)
  45. {
  46. case 1: realType = instruction.MakeGenericType(typeof(byte)); break;
  47. case 2: realType = instruction.MakeGenericType(typeof(ushort)); break;
  48. case 4: realType = instruction.MakeGenericType(typeof(uint)); break;
  49. case 8: realType = instruction.MakeGenericType(typeof(ulong)); break;
  50. default:
  51. throw new TamperCompilationException($"Invalid instruction width {width} in Atmosphere cheat");
  52. }
  53. return Activator.CreateInstance(realType, operands);
  54. }
  55. public static ulong GetImmediate(byte[] instruction, int index, int nybbleCount)
  56. {
  57. ulong value = 0;
  58. for (int i = 0; i < nybbleCount; i++)
  59. {
  60. value <<= 4;
  61. value |= instruction[index + i];
  62. }
  63. return value;
  64. }
  65. public static CodeType GetCodeType(byte[] instruction)
  66. {
  67. int codeType = instruction[CodeTypeIndex];
  68. if (codeType >= 0xC)
  69. {
  70. byte extension = instruction[CodeTypeIndex + 1];
  71. codeType = (codeType << 4) | extension;
  72. if (extension == 0xF)
  73. {
  74. extension = instruction[CodeTypeIndex + 2];
  75. codeType = (codeType << 4) | extension;
  76. }
  77. }
  78. return (CodeType)codeType;
  79. }
  80. public static byte[] ParseRawInstruction(string rawInstruction)
  81. {
  82. const int wordSize = 2 * sizeof(uint);
  83. // Instructions are multi-word, with 32bit words. Split the raw instruction
  84. // and parse each word into individual nybbles of bits.
  85. var words = rawInstruction.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
  86. byte[] instruction = new byte[wordSize * words.Length];
  87. if (words.Length == 0)
  88. {
  89. throw new TamperCompilationException("Empty instruction in Atmosphere cheat");
  90. }
  91. for (int wordIndex = 0; wordIndex < words.Length; wordIndex++)
  92. {
  93. string word = words[wordIndex];
  94. if (word.Length != wordSize)
  95. {
  96. throw new TamperCompilationException($"Invalid word length for {word} in Atmosphere cheat");
  97. }
  98. for (int nybbleIndex = 0; nybbleIndex < wordSize; nybbleIndex++)
  99. {
  100. int index = wordIndex * wordSize + nybbleIndex;
  101. instruction[index] = byte.Parse(word.AsSpan(nybbleIndex, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
  102. }
  103. }
  104. return instruction;
  105. }
  106. }
  107. }