RegisterConditional.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. using Ryujinx.HLE.Exceptions;
  2. using Ryujinx.HLE.HOS.Tamper.Conditions;
  3. using Ryujinx.HLE.HOS.Tamper.Operations;
  4. namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
  5. {
  6. /// <summary>
  7. /// Code type 0xC0 performs a comparison of the contents of a register and another value.
  8. /// This code support multiple operand types, see below. If the condition is not met,
  9. /// all instructions until the appropriate conditional block terminator are skipped.
  10. /// </summary>
  11. class RegisterConditional
  12. {
  13. private const int OperationWidthIndex = 2;
  14. private const int ComparisonTypeIndex = 3;
  15. private const int SourceRegisterIndex = 4;
  16. private const int OperandTypeIndex = 5;
  17. private const int RegisterOrMemoryRegionIndex = 6;
  18. private const int OffsetImmediateIndex = 7;
  19. private const int ValueImmediateIndex = 8;
  20. private const int MemoryRegionWithOffsetImmediate = 0;
  21. private const int MemoryRegionWithOffsetRegister = 1;
  22. private const int AddressRegisterWithOffsetImmediate = 2;
  23. private const int AddressRegisterWithOffsetRegister = 3;
  24. private const int OffsetImmediate = 4;
  25. private const int AddressRegister = 5;
  26. private const int OffsetImmediateSize = 9;
  27. private const int ValueImmediateSize8 = 8;
  28. private const int ValueImmediateSize16 = 16;
  29. public static ICondition Emit(byte[] instruction, CompilationContext context)
  30. {
  31. // C0TcSX##
  32. // C0TcS0Ma aaaaaaaa
  33. // C0TcS1Mr
  34. // C0TcS2Ra aaaaaaaa
  35. // C0TcS3Rr
  36. // C0TcS400 VVVVVVVV (VVVVVVVV)
  37. // C0TcS5X0
  38. // T: Width of memory write(1, 2, 4, or 8 bytes).
  39. // c: Condition to use, see below.
  40. // S: Source Register.
  41. // X: Operand Type, see below.
  42. // M: Memory Type(operand types 0 and 1).
  43. // R: Address Register(operand types 2 and 3).
  44. // a: Relative Address(operand types 0 and 2).
  45. // r: Offset Register(operand types 1 and 3).
  46. // X: Other Register(operand type 5).
  47. // V: Value to compare to(operand type 4).
  48. byte operationWidth = instruction[OperationWidthIndex];
  49. Comparison comparison = (Comparison)instruction[ComparisonTypeIndex];
  50. Register sourceRegister = context.GetRegister(instruction[SourceRegisterIndex]);
  51. byte operandType = instruction[OperandTypeIndex];
  52. byte registerOrMemoryRegion = instruction[RegisterOrMemoryRegionIndex];
  53. byte offsetRegisterIndex = instruction[OffsetImmediateIndex];
  54. ulong offsetImmediate;
  55. ulong valueImmediate;
  56. int valueImmediateSize;
  57. Register addressRegister;
  58. Register offsetRegister;
  59. IOperand sourceOperand;
  60. switch (operandType)
  61. {
  62. case MemoryRegionWithOffsetImmediate:
  63. // *(?x + #a)
  64. offsetImmediate = InstructionHelper.GetImmediate(instruction, OffsetImmediateIndex, OffsetImmediateSize);
  65. sourceOperand = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, offsetImmediate, context);
  66. break;
  67. case MemoryRegionWithOffsetRegister:
  68. // *(?x + $r)
  69. offsetRegister = context.GetRegister(offsetRegisterIndex);
  70. sourceOperand = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, offsetRegister, context);
  71. break;
  72. case AddressRegisterWithOffsetImmediate:
  73. // *($R + #a)
  74. addressRegister = context.GetRegister(registerOrMemoryRegion);
  75. offsetImmediate = InstructionHelper.GetImmediate(instruction, OffsetImmediateIndex, OffsetImmediateSize);
  76. sourceOperand = MemoryHelper.EmitPointer(addressRegister, offsetImmediate, context);
  77. break;
  78. case AddressRegisterWithOffsetRegister:
  79. // *($R + $r)
  80. addressRegister = context.GetRegister(registerOrMemoryRegion);
  81. offsetRegister = context.GetRegister(offsetRegisterIndex);
  82. sourceOperand = MemoryHelper.EmitPointer(addressRegister, offsetRegister, context);
  83. break;
  84. case OffsetImmediate:
  85. valueImmediateSize = operationWidth <= 4 ? ValueImmediateSize8 : ValueImmediateSize16;
  86. valueImmediate = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, valueImmediateSize);
  87. sourceOperand = new Value<ulong>(valueImmediate);
  88. break;
  89. case AddressRegister:
  90. // $V
  91. sourceOperand = context.GetRegister(registerOrMemoryRegion);
  92. break;
  93. default:
  94. throw new TamperCompilationException($"Invalid operand type {operandType} in Atmosphere cheat");
  95. }
  96. return InstructionHelper.CreateCondition(comparison, operationWidth, sourceRegister, sourceOperand);
  97. }
  98. }
  99. }