StoreConstantToMemory.cs 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  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 6 allows writing a fixed value to a memory address specified by a register.
  7. /// </summary>
  8. class StoreConstantToMemory
  9. {
  10. private const int OperationWidthIndex = 1;
  11. private const int AddressRegisterIndex = 3;
  12. private const int IncrementAddressRegisterIndex = 4;
  13. private const int UseOffsetRegisterIndex = 5;
  14. private const int OffsetRegisterIndex = 6;
  15. private const int ValueImmediateIndex = 8;
  16. private const int ValueImmediateSize = 16;
  17. public static void Emit(byte[] instruction, CompilationContext context)
  18. {
  19. // 6T0RIor0 VVVVVVVV VVVVVVVV
  20. // T: Width of memory write(1, 2, 4, or 8 bytes).
  21. // R: Register used as base memory address.
  22. // I: Increment register flag(0 = do not increment R, 1 = increment R by T).
  23. // o: Offset register enable flag(0 = do not add r to address, 1 = add r to address).
  24. // r: Register used as offset when o is 1.
  25. // V: Value to write to memory.
  26. byte operationWidth = instruction[OperationWidthIndex];
  27. Register sourceRegister = context.GetRegister(instruction[AddressRegisterIndex]);
  28. byte incrementAddressRegister = instruction[IncrementAddressRegisterIndex];
  29. byte useOffsetRegister = instruction[UseOffsetRegisterIndex];
  30. ulong immediate = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, ValueImmediateSize);
  31. Value<ulong> storeValue = new Value<ulong>(immediate);
  32. Pointer destinationMemory;
  33. switch (useOffsetRegister)
  34. {
  35. case 0:
  36. // Don't offset the address register by another register.
  37. destinationMemory = MemoryHelper.EmitPointer(sourceRegister, context);
  38. break;
  39. case 1:
  40. // Replace the source address by the sum of the base and offset registers.
  41. Register offsetRegister = context.GetRegister(instruction[OffsetRegisterIndex]);
  42. destinationMemory = MemoryHelper.EmitPointer(sourceRegister, offsetRegister, context);
  43. break;
  44. default:
  45. throw new TamperCompilationException($"Invalid offset mode {useOffsetRegister} in Atmosphere cheat");
  46. }
  47. InstructionHelper.EmitMov(operationWidth, context, destinationMemory, storeValue);
  48. switch (incrementAddressRegister)
  49. {
  50. case 0:
  51. // Don't increment the address register by operationWidth.
  52. break;
  53. case 1:
  54. // Increment the address register by operationWidth.
  55. IOperand increment = new Value<ulong>(operationWidth);
  56. context.CurrentOperations.Add(new OpAdd<ulong>(sourceRegister, sourceRegister, increment));
  57. break;
  58. default:
  59. throw new TamperCompilationException($"Invalid increment mode {incrementAddressRegister} in Atmosphere cheat");
  60. }
  61. }
  62. }
  63. }