StartEndLoop.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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 3 allows for iterating in a loop a fixed number of times.
  7. /// </summary>
  8. class StartEndLoop
  9. {
  10. private const int StartOrEndIndex = 1;
  11. private const int IterationRegisterIndex = 3;
  12. private const int IterationsImmediateIndex = 8;
  13. private const int IterationsImmediateSize = 8;
  14. private const byte LoopBegin = 0;
  15. private const byte LoopEnd = 1;
  16. public static void Emit(byte[] instruction, CompilationContext context)
  17. {
  18. // 300R0000 VVVVVVVV
  19. // R: Register to use as loop counter.
  20. // V: Number of iterations to loop.
  21. // 310R0000
  22. byte mode = instruction[StartOrEndIndex];
  23. byte iterationRegisterIndex = instruction[IterationRegisterIndex];
  24. switch (mode)
  25. {
  26. case LoopBegin:
  27. // Just start a new compilation block and parse the instruction itself at the end.
  28. context.BlockStack.Push(new OperationBlock(instruction));
  29. return;
  30. case LoopEnd:
  31. break;
  32. default:
  33. throw new TamperCompilationException($"Invalid loop {mode} in Atmosphere cheat");
  34. }
  35. // Use the loop begin instruction stored in the stack.
  36. instruction = context.CurrentBlock.BaseInstruction;
  37. CodeType codeType = InstructionHelper.GetCodeType(instruction);
  38. if (codeType != CodeType.StartEndLoop)
  39. {
  40. throw new TamperCompilationException($"Loop end does not match code type {codeType} in Atmosphere cheat");
  41. }
  42. // Validate if the register in the beginning and end are the same.
  43. byte oldIterationRegisterIndex = instruction[IterationRegisterIndex];
  44. if (iterationRegisterIndex != oldIterationRegisterIndex)
  45. {
  46. throw new TamperCompilationException($"The register used for the loop changed from {oldIterationRegisterIndex} to {iterationRegisterIndex} in Atmosphere cheat");
  47. }
  48. Register iterationRegister = context.GetRegister(iterationRegisterIndex);
  49. ulong immediate = InstructionHelper.GetImmediate(instruction, IterationsImmediateIndex, IterationsImmediateSize);
  50. // Create a loop block with the current operations and nest it in the upper
  51. // block of the stack.
  52. ForBlock block = new ForBlock(immediate, iterationRegister, context.CurrentOperations);
  53. context.BlockStack.Pop();
  54. context.CurrentOperations.Add(block);
  55. }
  56. }
  57. }