diff options
Diffstat (limited to 'src/Ryujinx.Cpu/LightningJit/Arm32/CodeGenContext.cs')
-rw-r--r-- | src/Ryujinx.Cpu/LightningJit/Arm32/CodeGenContext.cs | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/CodeGenContext.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/CodeGenContext.cs new file mode 100644 index 00000000..f55e2bb9 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/CodeGenContext.cs @@ -0,0 +1,198 @@ +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + class CodeGenContext + { + public CodeWriter CodeWriter { get; } + public Assembler Arm64Assembler { get; } + public RegisterAllocator RegisterAllocator { get; } + + public MemoryManagerType MemoryManagerType { get; } + + private uint _instructionAddress; + + public bool IsThumb { get; } + public uint Pc { get; private set; } + public bool InITBlock { get; private set; } + + private InstInfo _nextInstruction; + private bool _skipNextInstruction; + + private readonly ArmCondition[] _itConditions; + private int _itCount; + + private readonly List<PendingBranch> _pendingBranches; + + private bool _nzcvModified; + + public CodeGenContext(CodeWriter codeWriter, Assembler arm64Assembler, RegisterAllocator registerAllocator, MemoryManagerType mmType, bool isThumb) + { + CodeWriter = codeWriter; + Arm64Assembler = arm64Assembler; + RegisterAllocator = registerAllocator; + MemoryManagerType = mmType; + _itConditions = new ArmCondition[4]; + _pendingBranches = new(); + IsThumb = isThumb; + } + + public void SetPc(uint address) + { + // Due to historical reasons, the PC value is always 2 instructions ahead on 32-bit Arm CPUs. + Pc = address + (IsThumb ? 4u : 8u); + _instructionAddress = address; + } + + public void SetNextInstruction(InstInfo info) + { + _nextInstruction = info; + } + + public InstInfo PeekNextInstruction() + { + return _nextInstruction; + } + + public void SetSkipNextInstruction() + { + _skipNextInstruction = true; + } + + public bool ConsumeSkipNextInstruction() + { + bool skip = _skipNextInstruction; + _skipNextInstruction = false; + + return skip; + } + + public void AddPendingBranch(InstName name, int offset) + { + _pendingBranches.Add(new(BranchType.Branch, Pc + (uint)offset, 0u, name, CodeWriter.InstructionPointer)); + } + + public void AddPendingCall(uint targetAddress, uint nextAddress) + { + _pendingBranches.Add(new(BranchType.Call, targetAddress, nextAddress, InstName.BlI, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + RegisterAllocator.MarkGprAsUsed(RegisterUtils.LrRegister); + } + + public void AddPendingIndirectBranch(InstName name, uint targetRegister) + { + _pendingBranches.Add(new(BranchType.IndirectBranch, targetRegister, 0u, name, CodeWriter.InstructionPointer)); + + RegisterAllocator.MarkGprAsUsed((int)targetRegister); + } + + public void AddPendingTableBranch(uint rn, uint rm, bool halfword) + { + _pendingBranches.Add(new(halfword ? BranchType.TableBranchHalfword : BranchType.TableBranchByte, rn, rm, InstName.Tbb, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(2); + RegisterAllocator.MarkGprAsUsed((int)rn); + RegisterAllocator.MarkGprAsUsed((int)rm); + } + + public void AddPendingIndirectCall(uint targetRegister, uint nextAddress) + { + _pendingBranches.Add(new(BranchType.IndirectCall, targetRegister, nextAddress, InstName.BlxR, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(targetRegister == RegisterUtils.LrRegister ? 1 : 0); + RegisterAllocator.MarkGprAsUsed((int)targetRegister); + RegisterAllocator.MarkGprAsUsed(RegisterUtils.LrRegister); + } + + public void AddPendingSyncPoint() + { + _pendingBranches.Add(new(BranchType.SyncPoint, 0, 0, default, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public void AddPendingBkpt(uint imm) + { + _pendingBranches.Add(new(BranchType.SoftwareInterrupt, imm, _instructionAddress, InstName.Bkpt, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public void AddPendingSvc(uint imm) + { + _pendingBranches.Add(new(BranchType.SoftwareInterrupt, imm, _instructionAddress, InstName.Svc, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public void AddPendingUdf(uint imm) + { + _pendingBranches.Add(new(BranchType.SoftwareInterrupt, imm, _instructionAddress, InstName.Udf, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public void AddPendingReadCntpct(uint rt, uint rt2) + { + _pendingBranches.Add(new(BranchType.ReadCntpct, rt, rt2, InstName.Mrrc, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public IEnumerable<PendingBranch> GetPendingBranches() + { + return _pendingBranches; + } + + public void SetItBlockStart(ReadOnlySpan<ArmCondition> conditions) + { + _itCount = conditions.Length; + + for (int index = 0; index < conditions.Length; index++) + { + _itConditions[index] = conditions[index]; + } + + InITBlock = true; + } + + public bool ConsumeItCondition(out ArmCondition condition) + { + if (_itCount != 0) + { + condition = _itConditions[--_itCount]; + + return true; + } + + condition = ArmCondition.Al; + + return false; + } + + public void UpdateItState() + { + if (_itCount == 0) + { + InITBlock = false; + } + } + + public void SetNzcvModified() + { + _nzcvModified = true; + } + + public bool ConsumeNzcvModified() + { + bool modified = _nzcvModified; + _nzcvModified = false; + + return modified; + } + } +} |