Implement ARM32 memory instructions: LDM, LDR, LDRB, LDRD, LDRH, LDRSB, LDRSH, STM, STR, STRB, STRD, STRH (immediate and register + immediate variants), implement CMP (immediate and register shifted by immediate variants)

This commit is contained in:
gdkchan 2019-01-25 22:34:30 -02:00
commit 4f44eda3f0
16 changed files with 613 additions and 38 deletions

View file

@ -168,9 +168,50 @@ namespace ChocolArm64.Decoders
{ {
//Note: On ARM32, most ALU operations can write to R15 (PC), //Note: On ARM32, most ALU operations can write to R15 (PC),
//so we must consider such operations as a branch in potential aswell. //so we must consider such operations as a branch in potential aswell.
return opCode is IOpCodeBImm32 || if (opCode is IOpCodeAlu32 opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc)
opCode is IOpCodeBReg32 || {
(opCode is IOpCodeAlu32 op && op.Rd == RegisterAlias.Aarch32Pc); return true;
}
//Same thing for memory operations. We have the cases where PC is a target
//register (Rt == 15 or (mask & (1 << 15)) != 0), and cases where there is
//a write back to PC (wback == true && Rn == 15), however the later may
//be "undefined" depending on the CPU, so compilers should not produce that.
if (opCode is IOpCodeMem32 || opCode is IOpCodeMemMult32)
{
int rt, rn;
bool wBack;
if (opCode is IOpCodeMem32 opMem)
{
rt = opMem.Rt;
rn = opMem.Rn;
wBack = opMem.WBack;
}
else if (opCode is IOpCodeMemMult32 opMemMult)
{
const int pcMask = 1 << RegisterAlias.Aarch32Pc;
rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
rn = opMemMult.Rn;
wBack = opMemMult.PostOffset != 0;
}
else
{
throw new NotImplementedException($"The type \"{opCode.GetType().Name}\" is not implemented on the decoder.");
}
if ((rn == RegisterAlias.Aarch32Pc && wBack) ||
rt == RegisterAlias.Aarch32Pc)
{
return true;
}
}
//Explicit branch instructions.
return opCode is IOpCodeBImm32 ||
opCode is IOpCodeBReg32;
} }
private static bool IsException(OpCode64 opCode) private static bool IsException(OpCode64 opCode)

View file

@ -0,0 +1,10 @@
namespace ChocolArm64.Decoders
{
interface IOpCodeMem32 : IOpCode32
{
int Rt { get; }
int Rn { get; }
bool WBack { get; }
}
}

View file

@ -0,0 +1,11 @@
namespace ChocolArm64.Decoders
{
interface IOpCodeMemMult32 : IOpCode32
{
int Rn { get; }
int RegisterMask { get; }
int PostOffset { get; }
}
}

View file

@ -0,0 +1,15 @@
using ChocolArm64.Instructions;
namespace ChocolArm64.Decoders
{
class OpCode32MemImm8 : OpCodeMem32
{
public OpCode32MemImm8(Inst inst, long position, int opCode) : base(inst, position, opCode)
{
int imm4L = (opCode >> 0) & 0xf;
int imm4H = (opCode >> 8) & 0xf;
Imm = imm4L | (imm4H << 4);
}
}
}

View file

@ -0,0 +1,32 @@
using ChocolArm64.Instructions;
namespace ChocolArm64.Decoders
{
class OpCodeMem32 : OpCode32, IOpCodeMem32
{
public int Rt { get; private set; }
public int Rn { get; private set; }
public int Imm { get; protected set; }
public bool Index { get; private set; }
public bool Add { get; private set; }
public bool WBack { get; private set; }
public bool Unprivileged { get; private set; }
public OpCodeMem32(Inst inst, long position, int opCode) : base(inst, position, opCode)
{
Rt = (opCode >> 12) & 0xf;
Rn = (opCode >> 16) & 0xf;
bool w = (opCode & (1 << 21)) != 0;
bool u = (opCode & (1 << 23)) != 0;
bool p = (opCode & (1 << 24)) != 0;
Index = p;
Add = u;
WBack = !p || w;
Unprivileged = !p && w;
}
}
}

View file

@ -0,0 +1,12 @@
using ChocolArm64.Instructions;
namespace ChocolArm64.Decoders
{
class OpCodeMemImm32 : OpCodeMem32
{
public OpCodeMemImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
{
Imm = opCode & 0xfff;
}
}
}

View file

@ -0,0 +1,52 @@
using ChocolArm64.Instructions;
namespace ChocolArm64.Decoders
{
class OpCodeMemMult32 : OpCode32, IOpCodeMemMult32
{
public int Rn { get; private set; }
public int RegisterMask { get; private set; }
public int Offset { get; private set; }
public int PostOffset { get; private set; }
public OpCodeMemMult32(Inst inst, long position, int opCode) : base(inst, position, opCode)
{
Rn = (opCode >> 16) & 0xf;
bool w = (opCode & (1 << 21)) != 0;
bool u = (opCode & (1 << 23)) != 0;
bool p = (opCode & (1 << 24)) != 0;
RegisterMask = opCode & 0xffff;
int regsSize = 0;
for (int index = 0; index < 16; index++)
{
regsSize += (RegisterMask >> index) & 1;
}
regsSize *= 4;
if (!u)
{
Offset -= regsSize;
}
if (u == p)
{
Offset += 4;
}
if (w)
{
PostOffset = u ? regsSize : -regsSize;
}
else
{
PostOffset = 0;
}
}
}
}

View file

@ -2,6 +2,7 @@ using ChocolArm64.Decoders;
using ChocolArm64.State; using ChocolArm64.State;
using ChocolArm64.Translation; using ChocolArm64.Translation;
using System; using System;
using System.Reflection.Emit;
namespace ChocolArm64.Instructions namespace ChocolArm64.Instructions
{ {
@ -26,6 +27,51 @@ namespace ChocolArm64.Instructions
} }
} }
public static void EmitStoreToRegister(ILEmitterCtx context, int register)
{
if (register == RegisterAlias.Aarch32Pc)
{
context.EmitStoreState();
EmitBxWritePc(context);
}
else
{
context.EmitStint(GetRegisterAlias(context.Mode, register));
}
}
public static void EmitBxWritePc(ILEmitterCtx context)
{
context.Emit(OpCodes.Dup);
context.EmitLdc_I4(1);
context.Emit(OpCodes.And);
context.Emit(OpCodes.Dup);
context.EmitStflg((int)PState.TBit);
ILLabel lblArmMode = new ILLabel();
ILLabel lblEnd = new ILLabel();
context.Emit(OpCodes.Brtrue_S, lblArmMode);
context.EmitLdc_I4(~1);
context.Emit(OpCodes.Br_S, lblEnd);
context.MarkLabel(lblArmMode);
context.EmitLdc_I4(~3);
context.MarkLabel(lblEnd);
context.Emit(OpCodes.And);
context.Emit(OpCodes.Conv_U8);
context.Emit(OpCodes.Ret);
}
public static int GetRegisterAlias(Aarch32Mode mode, int register) public static int GetRegisterAlias(Aarch32Mode mode, int register)
{ {
//Only registers >= 8 are banked, with registers in the range [8, 12] being //Only registers >= 8 are banked, with registers in the range [8, 12] being

View file

@ -29,6 +29,22 @@ namespace ChocolArm64.Instructions
EmitAluStore(context); EmitAluStore(context);
} }
public static void Cmp(ILEmitterCtx context)
{
IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
EmitAluLoadOpers(context, setCarry: false);
context.Emit(OpCodes.Sub);
context.EmitZnFlagCheck();
EmitSubsCCheck(context);
EmitSubsVCheck(context);
context.Emit(OpCodes.Pop);
}
public static void Mov(ILEmitterCtx context) public static void Mov(ILEmitterCtx context)
{ {
IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp; IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
@ -106,6 +122,8 @@ namespace ChocolArm64.Instructions
private static void EmitAluWritePc(ILEmitterCtx context) private static void EmitAluWritePc(ILEmitterCtx context)
{ {
context.EmitStoreState();
if (IsThumb(context.CurrOp)) if (IsThumb(context.CurrOp))
{ {
context.EmitLdc_I4(~1); context.EmitLdc_I4(~1);

View file

@ -78,22 +78,5 @@ namespace ChocolArm64.Instructions
InstEmitFlowHelper.EmitCall(context, op.Imm); InstEmitFlowHelper.EmitCall(context, op.Imm);
} }
private static void EmitBxWritePc(ILEmitterCtx context)
{
context.Emit(OpCodes.Dup);
context.EmitLdc_I4(1);
context.Emit(OpCodes.And);
context.EmitStflg((int)PState.TBit);
context.EmitLdc_I4(~1);
context.Emit(OpCodes.And);
context.Emit(OpCodes.Conv_U8);
context.Emit(OpCodes.Ret);
}
} }
} }

View file

@ -0,0 +1,325 @@
using ChocolArm64.Decoders;
using ChocolArm64.State;
using ChocolArm64.Translation;
using System;
using System.Reflection.Emit;
using static ChocolArm64.Instructions.InstEmit32Helper;
using static ChocolArm64.Instructions.InstEmitMemoryHelper;
namespace ChocolArm64.Instructions
{
static partial class InstEmit32
{
private const int ByteSizeLog2 = 0;
private const int HWordSizeLog2 = 1;
private const int WordSizeLog2 = 2;
private const int DWordSizeLog2 = 3;
[Flags]
enum AccessType
{
Store = 0,
Signed = 1,
Load = 2,
LoadZx = Load,
LoadSx = Load | Signed,
}
public static void Ldm(ILEmitterCtx context)
{
OpCodeMemMult32 op = (OpCodeMemMult32)context.CurrOp;
EmitLoadFromRegister(context, op.Rn);
bool writesToPc = (op.RegisterMask & (1 << RegisterAlias.Aarch32Pc)) != 0;
bool writeBack = op.PostOffset != 0 && (op.Rn != RegisterAlias.Aarch32Pc || !writesToPc);
if (writeBack)
{
context.Emit(OpCodes.Dup);
}
context.EmitLdc_I4(op.Offset);
context.Emit(OpCodes.Add);
context.EmitSttmp();
if (writeBack)
{
context.EmitLdc_I4(op.PostOffset);
context.Emit(OpCodes.Add);
EmitStoreToRegister(context, op.Rn);
}
int mask = op.RegisterMask;
int offset = 0;
for (int register = 0; mask != 0; mask >>= 1, register++)
{
if ((mask & 1) != 0)
{
context.EmitLdarg(TranslatedSub.MemoryArgIdx);
context.EmitLdtmp();
context.EmitLdc_I4(offset);
context.Emit(OpCodes.Add);
EmitReadZxCall(context, WordSizeLog2);
EmitStoreToRegister(context, register);
offset += 4;
}
}
}
public static void Ldr(ILEmitterCtx context)
{
EmitLoadOrStore(context, WordSizeLog2, AccessType.LoadZx);
}
public static void Ldrb(ILEmitterCtx context)
{
EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx);
}
public static void Ldrd(ILEmitterCtx context)
{
EmitLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx);
}
public static void Ldrh(ILEmitterCtx context)
{
EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx);
}
public static void Ldrsb(ILEmitterCtx context)
{
EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadSx);
}
public static void Ldrsh(ILEmitterCtx context)
{
EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadSx);
}
public static void Stm(ILEmitterCtx context)
{
OpCodeMemMult32 op = (OpCodeMemMult32)context.CurrOp;
EmitLoadFromRegister(context, op.Rn);
context.EmitLdc_I4(op.Offset);
context.Emit(OpCodes.Add);
context.EmitSttmp();
int mask = op.RegisterMask;
int offset = 0;
for (int register = 0; mask != 0; mask >>= 1, register++)
{
if ((mask & 1) != 0)
{
context.EmitLdarg(TranslatedSub.MemoryArgIdx);
context.EmitLdtmp();
context.EmitLdc_I4(offset);
context.Emit(OpCodes.Add);
EmitLoadFromRegister(context, register);
EmitWriteCall(context, WordSizeLog2);
//Note: If Rn is also specified on the register list,
//and Rn is the first register on this list, then the
//value that is written to memory is the unmodified value,
//before the write back. If it is on the list, but it's
//not the first one, then the value written to memory
//varies between CPUs.
if (offset == 0 && op.PostOffset != 0)
{
//Emit write back after the first write.
EmitLoadFromRegister(context, op.Rn);
context.EmitLdc_I4(op.PostOffset);
context.Emit(OpCodes.Add);
EmitStoreToRegister(context, op.Rn);
}
offset += 4;
}
}
}
public static void Str(ILEmitterCtx context)
{
EmitLoadOrStore(context, WordSizeLog2, AccessType.Store);
}
public static void Strb(ILEmitterCtx context)
{
EmitLoadOrStore(context, ByteSizeLog2, AccessType.Store);
}
public static void Strd(ILEmitterCtx context)
{
EmitLoadOrStore(context, DWordSizeLog2, AccessType.Store);
}
public static void Strh(ILEmitterCtx context)
{
EmitLoadOrStore(context, HWordSizeLog2, AccessType.Store);
}
private static void EmitLoadOrStore(ILEmitterCtx context, int size, AccessType accType)
{
OpCodeMem32 op = (OpCodeMem32)context.CurrOp;
if (op.Index || op.WBack)
{
EmitLoadFromRegister(context, op.Rn);
context.EmitLdc_I4(op.Imm);
context.Emit(op.Add ? OpCodes.Add : OpCodes.Sub);
context.EmitSttmp();
}
context.EmitLdarg(TranslatedSub.MemoryArgIdx);
if (op.Index)
{
context.EmitLdtmp();
}
else
{
EmitLoadFromRegister(context, op.Rn);
}
if ((accType & AccessType.Load) != 0)
{
if ((accType & AccessType.Signed) != 0)
{
EmitReadSx32Call(context, size);
}
else
{
EmitReadZxCall(context, size);
}
if (op.WBack)
{
context.EmitLdtmp();
EmitStoreToRegister(context, op.Rn);
}
if (size == DWordSizeLog2)
{
context.Emit(OpCodes.Dup);
context.EmitLdflg((int)PState.EBit);
ILLabel lblBigEndian = new ILLabel();
ILLabel lblEnd = new ILLabel();
context.Emit(OpCodes.Brtrue_S, lblBigEndian);
//Little endian mode.
context.Emit(OpCodes.Conv_U4);
EmitStoreToRegister(context, op.Rt);
context.EmitLsr(32);
context.Emit(OpCodes.Conv_U4);
EmitStoreToRegister(context, op.Rt | 1);
context.Emit(OpCodes.Br_S, lblEnd);
//Big endian mode.
context.MarkLabel(lblBigEndian);
context.EmitLsr(32);
context.Emit(OpCodes.Conv_U4);
EmitStoreToRegister(context, op.Rt);
context.Emit(OpCodes.Conv_U4);
EmitStoreToRegister(context, op.Rt | 1);
context.MarkLabel(lblEnd);
}
else
{
EmitStoreToRegister(context, op.Rt);
}
}
else
{
if (op.WBack)
{
context.EmitLdtmp();
EmitStoreToRegister(context, op.Rn);
}
EmitLoadFromRegister(context, op.Rt);
if (size == DWordSizeLog2)
{
context.Emit(OpCodes.Conv_U8);
context.EmitLdflg((int)PState.EBit);
ILLabel lblBigEndian = new ILLabel();
ILLabel lblEnd = new ILLabel();
context.Emit(OpCodes.Brtrue_S, lblBigEndian);
//Little endian mode.
EmitLoadFromRegister(context, op.Rt | 1);
context.Emit(OpCodes.Conv_U8);
context.EmitLsl(32);
context.Emit(OpCodes.Or);
context.Emit(OpCodes.Br_S, lblEnd);
//Big endian mode.
context.MarkLabel(lblBigEndian);
context.EmitLsl(32);
EmitLoadFromRegister(context, op.Rt | 1);
context.Emit(OpCodes.Conv_U8);
context.Emit(OpCodes.Or);
context.MarkLabel(lblEnd);
}
EmitWriteCall(context, size);
}
}
}
}

View file

@ -37,18 +37,32 @@ namespace ChocolArm64
{ {
#region "OpCode Table (AArch32)" #region "OpCode Table (AArch32)"
//Integer //Integer
SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Add, typeof(OpCodeAluImm32)); SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Add, typeof(OpCodeAluImm32));
SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Add, typeof(OpCodeAluRsImm32)); SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Add, typeof(OpCodeAluRsImm32));
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.B, typeof(OpCodeBImm32)); SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.B, typeof(OpCodeBImm32));
SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Bl, typeof(OpCodeBImm32)); SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Bl, typeof(OpCodeBImm32));
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Blx, typeof(OpCodeBImm32)); SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Blx, typeof(OpCodeBImm32));
SetA32("<<<<000100101111111111110001xxxx", InstEmit32.Bx, typeof(OpCodeBReg32)); SetA32("<<<<000100101111111111110001xxxx", InstEmit32.Bx, typeof(OpCodeBReg32));
SetT32( "010001110xxxx000", InstEmit32.Bx, typeof(OpCodeBRegT16)); SetT32("010001110xxxx000", InstEmit32.Bx, typeof(OpCodeBRegT16));
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstEmit32.Mov, typeof(OpCodeAluImm32)); SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstEmit32.Cmp, typeof(OpCodeAluImm32));
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstEmit32.Mov, typeof(OpCodeAluRsImm32)); SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstEmit32.Cmp, typeof(OpCodeAluRsImm32));
SetT32( "00100xxxxxxxxxxx", InstEmit32.Mov, typeof(OpCodeAluImm8T16)); SetA32("<<<<100xx0x1xxxxxxxxxxxxxxxxxxxx", InstEmit32.Ldm, typeof(OpCodeMemMult32));
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Sub, typeof(OpCodeAluImm32)); SetA32("<<<<010xx0x1xxxxxxxxxxxxxxxxxxxx", InstEmit32.Ldr, typeof(OpCodeMemImm32));
SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Sub, typeof(OpCodeAluRsImm32)); SetA32("<<<<010xx1x1xxxxxxxxxxxxxxxxxxxx", InstEmit32.Ldrb, typeof(OpCodeMemImm32));
SetA32("<<<<000xx1x0xxxxxxxxxxxx1101xxxx", InstEmit32.Ldrd, typeof(OpCode32MemImm8));
SetA32("<<<<000xx1x1xxxxxxxxxxxx1011xxxx", InstEmit32.Ldrh, typeof(OpCode32MemImm8));
SetA32("<<<<000xx1x1xxxxxxxxxxxx1101xxxx", InstEmit32.Ldrsb, typeof(OpCode32MemImm8));
SetA32("<<<<000xx1x1xxxxxxxxxxxx1111xxxx", InstEmit32.Ldrsh, typeof(OpCode32MemImm8));
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstEmit32.Mov, typeof(OpCodeAluImm32));
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstEmit32.Mov, typeof(OpCodeAluRsImm32));
SetT32("00100xxxxxxxxxxx", InstEmit32.Mov, typeof(OpCodeAluImm8T16));
SetA32("<<<<100xx0x0xxxxxxxxxxxxxxxxxxxx", InstEmit32.Stm, typeof(OpCodeMemMult32));
SetA32("<<<<010xx0x0xxxxxxxxxxxxxxxxxxxx", InstEmit32.Str, typeof(OpCodeMemImm32));
SetA32("<<<<010xx1x0xxxxxxxxxxxxxxxxxxxx", InstEmit32.Strb, typeof(OpCodeMemImm32));
SetA32("<<<<000xx1x0xxxxxxxxxxxx1111xxxx", InstEmit32.Strd, typeof(OpCode32MemImm8));
SetA32("<<<<000xx1x0xxxxxxxxxxxx1011xxxx", InstEmit32.Strh, typeof(OpCode32MemImm8));
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Sub, typeof(OpCodeAluImm32));
SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Sub, typeof(OpCodeAluRsImm32));
#endregion #endregion
#region "OpCode Table (AArch64)" #region "OpCode Table (AArch64)"

View file

@ -13,7 +13,7 @@ namespace ChocolArm64.State
private const int MinInstForCheck = 4000000; private const int MinInstForCheck = 4000000;
public bool Thumb;
public ulong X0, X1, X2, X3, X4, X5, X6, X7, public ulong X0, X1, X2, X3, X4, X5, X6, X7,
X8, X9, X10, X11, X12, X13, X14, X15, X8, X9, X10, X11, X12, X13, X14, X15,
@ -25,13 +25,16 @@ namespace ChocolArm64.State
V16, V17, V18, V19, V20, V21, V22, V23, V16, V17, V18, V19, V20, V21, V22, V23,
V24, V25, V26, V27, V28, V29, V30, V31; V24, V25, V26, V27, V28, V29, V30, V31;
public bool Aarch32;
public bool Thumb;
public bool BigEndian;
public bool Overflow; public bool Overflow;
public bool Carry; public bool Carry;
public bool Zero; public bool Zero;
public bool Negative; public bool Negative;
public bool IsAarch32;
public int ElrHyp; public int ElrHyp;
public bool Running { get; set; } public bool Running { get; set; }
@ -140,7 +143,7 @@ namespace ChocolArm64.State
internal ExecutionMode GetExecutionMode() internal ExecutionMode GetExecutionMode()
{ {
if (!IsAarch32) if (!Aarch32)
{ {
return ExecutionMode.Aarch64; return ExecutionMode.Aarch64;
} }

View file

@ -6,6 +6,7 @@ namespace ChocolArm64.State
enum PState enum PState
{ {
TBit = 5, TBit = 5,
EBit = 9,
VBit = 28, VBit = 28,
CBit = 29, CBit = 29,
@ -13,6 +14,7 @@ namespace ChocolArm64.State
NBit = 31, NBit = 31,
T = 1 << TBit, T = 1 << TBit,
E = 1 << EBit,
V = 1 << VBit, V = 1 << VBit,
C = 1 << CBit, C = 1 << CBit,

View file

@ -44,6 +44,7 @@ namespace ChocolArm64.State
switch ((PState)Index) switch ((PState)Index)
{ {
case PState.TBit: return GetField(nameof(CpuThreadState.Thumb)); case PState.TBit: return GetField(nameof(CpuThreadState.Thumb));
case PState.EBit: return GetField(nameof(CpuThreadState.BigEndian));
case PState.VBit: return GetField(nameof(CpuThreadState.Overflow)); case PState.VBit: return GetField(nameof(CpuThreadState.Overflow));
case PState.CBit: return GetField(nameof(CpuThreadState.Carry)); case PState.CBit: return GetField(nameof(CpuThreadState.Carry));

View file

@ -152,10 +152,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
Context = new CpuThread(owner.Translator, owner.CpuMemory, (long)entrypoint); Context = new CpuThread(owner.Translator, owner.CpuMemory, (long)entrypoint);
Context.ThreadState.IsAarch32 = (Owner.MmuFlags & 1) == 0; bool isAarch32 = (Owner.MmuFlags & 1) == 0;
Context.ThreadState.Aarch32 = isAarch32;
Context.ThreadState.X0 = argsPtr; Context.ThreadState.X0 = argsPtr;
Context.ThreadState.X31 = stackTop;
if (isAarch32)
{
Context.ThreadState.X13 = (uint)stackTop;
}
else
{
Context.ThreadState.X31 = stackTop;
}
Context.ThreadState.CntfrqEl0 = 19200000; Context.ThreadState.CntfrqEl0 = 19200000;
Context.ThreadState.Tpidr = (long)_tlsAddress; Context.ThreadState.Tpidr = (long)_tlsAddress;