CodeGenContext.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using ARMeilleure.Memory;
  2. using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
  3. using System;
  4. using System.Collections.Generic;
  5. namespace Ryujinx.Cpu.LightningJit.Arm32
  6. {
  7. class CodeGenContext
  8. {
  9. public CodeWriter CodeWriter { get; }
  10. public Assembler Arm64Assembler { get; }
  11. public RegisterAllocator RegisterAllocator { get; }
  12. public MemoryManagerType MemoryManagerType { get; }
  13. private uint _instructionAddress;
  14. public bool IsThumb { get; }
  15. public uint Pc { get; private set; }
  16. public bool InITBlock { get; private set; }
  17. private InstInfo _nextInstruction;
  18. private bool _skipNextInstruction;
  19. private readonly ArmCondition[] _itConditions;
  20. private int _itCount;
  21. private readonly List<PendingBranch> _pendingBranches;
  22. private bool _nzcvModified;
  23. public CodeGenContext(CodeWriter codeWriter, Assembler arm64Assembler, RegisterAllocator registerAllocator, MemoryManagerType mmType, bool isThumb)
  24. {
  25. CodeWriter = codeWriter;
  26. Arm64Assembler = arm64Assembler;
  27. RegisterAllocator = registerAllocator;
  28. MemoryManagerType = mmType;
  29. _itConditions = new ArmCondition[4];
  30. _pendingBranches = [];
  31. IsThumb = isThumb;
  32. }
  33. public void SetPc(uint address)
  34. {
  35. // Due to historical reasons, the PC value is always 2 instructions ahead on 32-bit Arm CPUs.
  36. Pc = address + (IsThumb ? 4u : 8u);
  37. _instructionAddress = address;
  38. }
  39. public void SetNextInstruction(InstInfo info)
  40. {
  41. _nextInstruction = info;
  42. }
  43. public InstInfo PeekNextInstruction()
  44. {
  45. return _nextInstruction;
  46. }
  47. public void SetSkipNextInstruction()
  48. {
  49. _skipNextInstruction = true;
  50. }
  51. public bool ConsumeSkipNextInstruction()
  52. {
  53. bool skip = _skipNextInstruction;
  54. _skipNextInstruction = false;
  55. return skip;
  56. }
  57. public void AddPendingBranch(InstName name, int offset)
  58. {
  59. _pendingBranches.Add(new(BranchType.Branch, Pc + (uint)offset, 0u, name, CodeWriter.InstructionPointer));
  60. }
  61. public void AddPendingCall(uint targetAddress, uint nextAddress)
  62. {
  63. _pendingBranches.Add(new(BranchType.Call, targetAddress, nextAddress, InstName.BlI, CodeWriter.InstructionPointer));
  64. RegisterAllocator.EnsureTempGprRegisters(1);
  65. RegisterAllocator.MarkGprAsUsed(RegisterUtils.LrRegister);
  66. }
  67. public void AddPendingIndirectBranch(InstName name, uint targetRegister)
  68. {
  69. _pendingBranches.Add(new(BranchType.IndirectBranch, targetRegister, 0u, name, CodeWriter.InstructionPointer));
  70. RegisterAllocator.MarkGprAsUsed((int)targetRegister);
  71. }
  72. public void AddPendingTableBranch(uint rn, uint rm, bool halfword)
  73. {
  74. _pendingBranches.Add(new(halfword ? BranchType.TableBranchHalfword : BranchType.TableBranchByte, rn, rm, InstName.Tbb, CodeWriter.InstructionPointer));
  75. RegisterAllocator.EnsureTempGprRegisters(2);
  76. RegisterAllocator.MarkGprAsUsed((int)rn);
  77. RegisterAllocator.MarkGprAsUsed((int)rm);
  78. }
  79. public void AddPendingIndirectCall(uint targetRegister, uint nextAddress)
  80. {
  81. _pendingBranches.Add(new(BranchType.IndirectCall, targetRegister, nextAddress, InstName.BlxR, CodeWriter.InstructionPointer));
  82. RegisterAllocator.EnsureTempGprRegisters(targetRegister == RegisterUtils.LrRegister ? 1 : 0);
  83. RegisterAllocator.MarkGprAsUsed((int)targetRegister);
  84. RegisterAllocator.MarkGprAsUsed(RegisterUtils.LrRegister);
  85. }
  86. public void AddPendingSyncPoint()
  87. {
  88. _pendingBranches.Add(new(BranchType.SyncPoint, 0, 0, default, CodeWriter.InstructionPointer));
  89. RegisterAllocator.EnsureTempGprRegisters(1);
  90. }
  91. public void AddPendingBkpt(uint imm)
  92. {
  93. _pendingBranches.Add(new(BranchType.SoftwareInterrupt, imm, _instructionAddress, InstName.Bkpt, CodeWriter.InstructionPointer));
  94. RegisterAllocator.EnsureTempGprRegisters(1);
  95. }
  96. public void AddPendingSvc(uint imm)
  97. {
  98. _pendingBranches.Add(new(BranchType.SoftwareInterrupt, imm, _instructionAddress, InstName.Svc, CodeWriter.InstructionPointer));
  99. RegisterAllocator.EnsureTempGprRegisters(1);
  100. }
  101. public void AddPendingUdf(uint imm)
  102. {
  103. _pendingBranches.Add(new(BranchType.SoftwareInterrupt, imm, _instructionAddress, InstName.Udf, CodeWriter.InstructionPointer));
  104. RegisterAllocator.EnsureTempGprRegisters(1);
  105. }
  106. public void AddPendingReadCntpct(uint rt, uint rt2)
  107. {
  108. _pendingBranches.Add(new(BranchType.ReadCntpct, rt, rt2, InstName.Mrrc, CodeWriter.InstructionPointer));
  109. RegisterAllocator.EnsureTempGprRegisters(1);
  110. }
  111. public IEnumerable<PendingBranch> GetPendingBranches()
  112. {
  113. return _pendingBranches;
  114. }
  115. public void SetItBlockStart(ReadOnlySpan<ArmCondition> conditions)
  116. {
  117. _itCount = conditions.Length;
  118. for (int index = 0; index < conditions.Length; index++)
  119. {
  120. _itConditions[index] = conditions[index];
  121. }
  122. InITBlock = true;
  123. }
  124. public bool ConsumeItCondition(out ArmCondition condition)
  125. {
  126. if (_itCount != 0)
  127. {
  128. condition = _itConditions[--_itCount];
  129. return true;
  130. }
  131. condition = ArmCondition.Al;
  132. return false;
  133. }
  134. public void UpdateItState()
  135. {
  136. if (_itCount == 0)
  137. {
  138. InITBlock = false;
  139. }
  140. }
  141. public void SetNzcvModified()
  142. {
  143. _nzcvModified = true;
  144. }
  145. public bool ConsumeNzcvModified()
  146. {
  147. bool modified = _nzcvModified;
  148. _nzcvModified = false;
  149. return modified;
  150. }
  151. }
  152. }