StoreRegisterToMemory.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. using Ryujinx.HLE.Exceptions;
  2. using Ryujinx.HLE.HOS.Tamper.Operations;
  3. namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
  4. {
  5. /// <summary>
  6. /// Code type 10 allows writing a register to memory.
  7. /// </summary>
  8. class StoreRegisterToMemory
  9. {
  10. private const int OperationWidthIndex = 1;
  11. private const int SourceRegisterIndex = 2;
  12. private const int AddressRegisterIndex = 3;
  13. private const int IncrementAddressRegisterIndex = 4;
  14. private const int AddressingTypeIndex = 5;
  15. private const int RegisterOrMemoryRegionIndex = 6;
  16. private const int OffsetImmediateIndex = 7;
  17. private const int AddressRegister = 0;
  18. private const int AddressRegisterWithOffsetRegister = 1;
  19. private const int OffsetImmediate = 2;
  20. private const int MemoryRegionWithOffsetRegister = 3;
  21. private const int MemoryRegionWithOffsetImmediate = 4;
  22. private const int MemoryRegionWithOffsetRegisterAndImmediate = 5;
  23. private const int OffsetImmediateSize1 = 1;
  24. private const int OffsetImmediateSize9 = 9;
  25. public static void Emit(byte[] instruction, CompilationContext context)
  26. {
  27. // ATSRIOxa (aaaaaaaa)
  28. // T: Width of memory write (1, 2, 4, or 8 bytes).
  29. // S: Register to write to memory.
  30. // R: Register to use as base address.
  31. // I: Increment register flag (0 = do not increment R, 1 = increment R by T).
  32. // O: Offset type, see below.
  33. // x: Register used as offset when O is 1, Memory type when O is 3, 4 or 5.
  34. // a: Value used as offset when O is 2, 4 or 5.
  35. byte operationWidth = instruction[OperationWidthIndex];
  36. Register sourceRegister = context.GetRegister(instruction[SourceRegisterIndex]);
  37. Register addressRegister = context.GetRegister(instruction[AddressRegisterIndex]);
  38. byte incrementAddressRegister = instruction[IncrementAddressRegisterIndex];
  39. byte offsetType = instruction[AddressingTypeIndex];
  40. byte registerOrMemoryRegion = instruction[RegisterOrMemoryRegionIndex];
  41. int immediateSize = instruction.Length <= 8 ? OffsetImmediateSize1 : OffsetImmediateSize9;
  42. ulong immediate = InstructionHelper.GetImmediate(instruction, OffsetImmediateIndex, immediateSize);
  43. Pointer destinationMemory;
  44. switch (offsetType)
  45. {
  46. case AddressRegister:
  47. // *($R) = $S
  48. destinationMemory = MemoryHelper.EmitPointer(addressRegister, context);
  49. break;
  50. case AddressRegisterWithOffsetRegister:
  51. // *($R + $x) = $S
  52. Register offsetRegister = context.GetRegister(registerOrMemoryRegion);
  53. destinationMemory = MemoryHelper.EmitPointer(addressRegister, offsetRegister, context);
  54. break;
  55. case OffsetImmediate:
  56. // *(#a) = $S
  57. destinationMemory = MemoryHelper.EmitPointer(addressRegister, immediate, context);
  58. break;
  59. case MemoryRegionWithOffsetRegister:
  60. // *(?x + $R) = $S
  61. destinationMemory = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, addressRegister, context);
  62. break;
  63. case MemoryRegionWithOffsetImmediate:
  64. // *(?x + #a) = $S
  65. destinationMemory = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, immediate, context);
  66. break;
  67. case MemoryRegionWithOffsetRegisterAndImmediate:
  68. // *(?x + #a + $R) = $S
  69. destinationMemory = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, addressRegister, immediate, context);
  70. break;
  71. default:
  72. throw new TamperCompilationException($"Invalid offset type {offsetType} in Atmosphere cheat");
  73. }
  74. InstructionHelper.EmitMov(operationWidth, context, destinationMemory, sourceRegister);
  75. switch (incrementAddressRegister)
  76. {
  77. case 0:
  78. // Don't increment the address register by operationWidth.
  79. break;
  80. case 1:
  81. // Increment the address register by operationWidth.
  82. IOperand increment = new Value<ulong>(operationWidth);
  83. context.CurrentOperations.Add(new OpAdd<ulong>(addressRegister, addressRegister, increment));
  84. break;
  85. default:
  86. throw new TamperCompilationException($"Invalid increment mode {incrementAddressRegister} in Atmosphere cheat");
  87. }
  88. }
  89. }
  90. }