forked from Mirror/Ryujinx
Implement some ARM32 memory instructions and CMP (#565)
* 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) * Rename some opcode classes and flag masks for consistency * Fix a few suboptimal ARM32 codegen issues, only loads should be considered on decoder when checking if Rt == PC, and only NZCV flags should be considered for comparison optimizations * Take into account Rt2 for LDRD instructions aswell when checking if the instruction changes PC * Re-align arm32 instructions on the opcode table
This commit is contained in:
parent
8f7fcede7f
commit
c1bdf19061
29 changed files with 686 additions and 87 deletions
|
@ -168,9 +168,59 @@ 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 IOpCode32Alu 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 IOpCode32Mem || opCode is IOpCode32MemMult)
|
||||||
|
{
|
||||||
|
int rt, rn;
|
||||||
|
|
||||||
|
bool wBack, isLoad;
|
||||||
|
|
||||||
|
if (opCode is IOpCode32Mem opMem)
|
||||||
|
{
|
||||||
|
rt = opMem.Rt;
|
||||||
|
rn = opMem.Rn;
|
||||||
|
wBack = opMem.WBack;
|
||||||
|
isLoad = opMem.IsLoad;
|
||||||
|
|
||||||
|
//For the dual load, we also need to take into account the
|
||||||
|
//case were Rt2 == 15 (PC).
|
||||||
|
if (rt == 14 && opMem.Emitter == InstEmit32.Ldrd)
|
||||||
|
{
|
||||||
|
rt = RegisterAlias.Aarch32Pc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (opCode is IOpCode32MemMult opMemMult)
|
||||||
|
{
|
||||||
|
const int pcMask = 1 << RegisterAlias.Aarch32Pc;
|
||||||
|
|
||||||
|
rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
|
||||||
|
rn = opMemMult.Rn;
|
||||||
|
wBack = opMemMult.PostOffset != 0;
|
||||||
|
isLoad = opMemMult.IsLoad;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"The type \"{opCode.GetType().Name}\" is not implemented on the decoder.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rt == RegisterAlias.Aarch32Pc && isLoad) ||
|
||||||
|
(rn == RegisterAlias.Aarch32Pc && wBack))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Explicit branch instructions.
|
||||||
|
return opCode is IOpCode32BImm ||
|
||||||
|
opCode is IOpCode32BReg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsException(OpCode64 opCode)
|
private static bool IsException(OpCode64 opCode)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
interface IOpCodeAlu32 : IOpCode32
|
interface IOpCode32Alu : IOpCode32
|
||||||
{
|
{
|
||||||
int Rd { get; }
|
int Rd { get; }
|
||||||
int Rn { get; }
|
int Rn { get; }
|
4
ChocolArm64/Decoders/IOpCode32BImm.cs
Normal file
4
ChocolArm64/Decoders/IOpCode32BImm.cs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32BImm : IOpCode32, IOpCodeBImm { }
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
interface IOpCodeBReg32 : IOpCode32
|
interface IOpCode32BReg : IOpCode32
|
||||||
{
|
{
|
||||||
int Rm { get; }
|
int Rm { get; }
|
||||||
}
|
}
|
12
ChocolArm64/Decoders/IOpCode32Mem.cs
Normal file
12
ChocolArm64/Decoders/IOpCode32Mem.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32Mem : IOpCode32
|
||||||
|
{
|
||||||
|
int Rt { get; }
|
||||||
|
int Rn { get; }
|
||||||
|
|
||||||
|
bool WBack { get; }
|
||||||
|
|
||||||
|
bool IsLoad { get; }
|
||||||
|
}
|
||||||
|
}
|
13
ChocolArm64/Decoders/IOpCode32MemMult.cs
Normal file
13
ChocolArm64/Decoders/IOpCode32MemMult.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32MemMult : IOpCode32
|
||||||
|
{
|
||||||
|
int Rn { get; }
|
||||||
|
|
||||||
|
int RegisterMask { get; }
|
||||||
|
|
||||||
|
int PostOffset { get; }
|
||||||
|
|
||||||
|
bool IsLoad { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
namespace ChocolArm64.Decoders
|
|
||||||
{
|
|
||||||
interface IOpCodeBImm32 : IOpCode32, IOpCodeBImm { }
|
|
||||||
}
|
|
|
@ -2,14 +2,14 @@ using ChocolArm64.Instructions;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeAlu32 : OpCode32, IOpCodeAlu32
|
class OpCode32Alu : OpCode32, IOpCode32Alu
|
||||||
{
|
{
|
||||||
public int Rd { get; private set; }
|
public int Rd { get; private set; }
|
||||||
public int Rn { get; private set; }
|
public int Rn { get; private set; }
|
||||||
|
|
||||||
public bool SetFlags { get; private set; }
|
public bool SetFlags { get; private set; }
|
||||||
|
|
||||||
public OpCodeAlu32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCode32Alu(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
Rd = (opCode >> 12) & 0xf;
|
Rd = (opCode >> 12) & 0xf;
|
||||||
Rn = (opCode >> 16) & 0xf;
|
Rn = (opCode >> 16) & 0xf;
|
|
@ -2,13 +2,13 @@ using ChocolArm64.Instructions;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeAluImm32 : OpCodeAlu32
|
class OpCode32AluImm : OpCode32Alu
|
||||||
{
|
{
|
||||||
public int Imm { get; private set; }
|
public int Imm { get; private set; }
|
||||||
|
|
||||||
public bool IsRotated { get; private set; }
|
public bool IsRotated { get; private set; }
|
||||||
|
|
||||||
public OpCodeAluImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCode32AluImm(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
int value = (opCode >> 0) & 0xff;
|
int value = (opCode >> 0) & 0xff;
|
||||||
int shift = (opCode >> 8) & 0xf;
|
int shift = (opCode >> 8) & 0xf;
|
|
@ -2,14 +2,14 @@ using ChocolArm64.Instructions;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeAluRsImm32 : OpCodeAlu32
|
class OpCode32AluRsImm : OpCode32Alu
|
||||||
{
|
{
|
||||||
public int Rm { get; private set; }
|
public int Rm { get; private set; }
|
||||||
public int Imm { get; private set; }
|
public int Imm { get; private set; }
|
||||||
|
|
||||||
public ShiftType ShiftType { get; private set; }
|
public ShiftType ShiftType { get; private set; }
|
||||||
|
|
||||||
public OpCodeAluRsImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCode32AluRsImm(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
Rm = (opCode >> 0) & 0xf;
|
Rm = (opCode >> 0) & 0xf;
|
||||||
Imm = (opCode >> 7) & 0x1f;
|
Imm = (opCode >> 7) & 0x1f;
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instructions;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeBImm32 : OpCode32, IOpCodeBImm32
|
class OpCode32BImm : OpCode32, IOpCode32BImm
|
||||||
{
|
{
|
||||||
public long Imm { get; private set; }
|
public long Imm { get; private set; }
|
||||||
|
|
||||||
public OpCodeBImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCode32BImm(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
uint pc = GetPc();
|
uint pc = GetPc();
|
||||||
|
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instructions;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeBReg32 : OpCode32, IOpCodeBReg32
|
class OpCode32BReg : OpCode32, IOpCode32BReg
|
||||||
{
|
{
|
||||||
public int Rm { get; private set; }
|
public int Rm { get; private set; }
|
||||||
|
|
||||||
public OpCodeBReg32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCode32BReg(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
Rm = opCode & 0xf;
|
Rm = opCode & 0xf;
|
||||||
}
|
}
|
37
ChocolArm64/Decoders/OpCode32Mem.cs
Normal file
37
ChocolArm64/Decoders/OpCode32Mem.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32Mem : OpCode32, IOpCode32Mem
|
||||||
|
{
|
||||||
|
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 bool IsLoad { get; private set; }
|
||||||
|
|
||||||
|
public OpCode32Mem(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 12) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
bool isLoad = (opCode & (1 << 20)) != 0;
|
||||||
|
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;
|
||||||
|
|
||||||
|
IsLoad = isLoad || inst.Emitter == InstEmit32.Ldrd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
ChocolArm64/Decoders/OpCode32MemImm.cs
Normal file
12
ChocolArm64/Decoders/OpCode32MemImm.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32MemImm : OpCode32Mem
|
||||||
|
{
|
||||||
|
public OpCode32MemImm(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
Imm = opCode & 0xfff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
ChocolArm64/Decoders/OpCode32MemImm8.cs
Normal file
15
ChocolArm64/Decoders/OpCode32MemImm8.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32MemImm8 : OpCode32Mem
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
ChocolArm64/Decoders/OpCode32MemMult.cs
Normal file
57
ChocolArm64/Decoders/OpCode32MemMult.cs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32MemMult : OpCode32, IOpCode32MemMult
|
||||||
|
{
|
||||||
|
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 bool IsLoad { get; private set; }
|
||||||
|
|
||||||
|
public OpCode32MemMult(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
bool isLoad = (opCode & (1 << 20)) != 0;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsLoad = isLoad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Instructions;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeAluImm8T16 : OpCodeT16, IOpCodeAlu32
|
class OpCodeT16AluImm8 : OpCodeT16, IOpCode32Alu
|
||||||
{
|
{
|
||||||
private int _rdn;
|
private int _rdn;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
public int Imm { get; private set; }
|
public int Imm { get; private set; }
|
||||||
|
|
||||||
public OpCodeAluImm8T16(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCodeT16AluImm8(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
Imm = (opCode >> 0) & 0xff;
|
Imm = (opCode >> 0) & 0xff;
|
||||||
_rdn = (opCode >> 8) & 0x7;
|
_rdn = (opCode >> 8) & 0x7;
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instructions;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeBRegT16 : OpCodeT16, IOpCodeBReg32
|
class OpCodeT16BReg : OpCodeT16, IOpCode32BReg
|
||||||
{
|
{
|
||||||
public int Rm { get; private set; }
|
public int Rm { get; private set; }
|
||||||
|
|
||||||
public OpCodeBRegT16(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCodeT16BReg(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
Rm = (opCode >> 3) & 0xf;
|
Rm = (opCode >> 3) & 0xf;
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
public static void Add(ILEmitterCtx context)
|
public static void Add(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
|
|
||||||
EmitAluLoadOpers(context, setCarry: false);
|
EmitAluLoadOpers(context, setCarry: false);
|
||||||
|
|
||||||
|
@ -29,9 +29,25 @@ namespace ChocolArm64.Instructions
|
||||||
EmitAluStore(context);
|
EmitAluStore(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Cmp(ILEmitterCtx context)
|
||||||
|
{
|
||||||
|
IOpCode32Alu op = (IOpCode32Alu)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;
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
|
|
||||||
EmitAluLoadOper2(context);
|
EmitAluLoadOper2(context);
|
||||||
|
|
||||||
|
@ -45,7 +61,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void Sub(ILEmitterCtx context)
|
public static void Sub(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
|
|
||||||
EmitAluLoadOpers(context, setCarry: false);
|
EmitAluLoadOpers(context, setCarry: false);
|
||||||
|
|
||||||
|
@ -64,7 +80,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
private static void EmitAluStore(ILEmitterCtx context)
|
private static void EmitAluStore(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
|
|
||||||
if (op.Rd == RegisterAlias.Aarch32Pc)
|
if (op.Rd == RegisterAlias.Aarch32Pc)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -127,7 +127,7 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
context.EmitLdintzr(op.Rm);
|
context.EmitLdintzr(op.Rm);
|
||||||
}
|
}
|
||||||
else if (context.CurrOp is OpCodeAluRsImm32 op32)
|
else if (context.CurrOp is OpCode32AluRsImm op32)
|
||||||
{
|
{
|
||||||
InstEmit32Helper.EmitLoadFromRegister(context, op32.Rm);
|
InstEmit32Helper.EmitLoadFromRegister(context, op32.Rm);
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ namespace ChocolArm64.Instructions
|
||||||
context.EmitLdint(op.Rn);
|
context.EmitLdint(op.Rn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (context.CurrOp is IOpCodeAlu32 op32)
|
else if (context.CurrOp is IOpCode32Alu op32)
|
||||||
{
|
{
|
||||||
InstEmit32Helper.EmitLoadFromRegister(context, op32.Rn);
|
InstEmit32Helper.EmitLoadFromRegister(context, op32.Rn);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ namespace ChocolArm64.Instructions
|
||||||
switch (context.CurrOp)
|
switch (context.CurrOp)
|
||||||
{
|
{
|
||||||
//ARM32.
|
//ARM32.
|
||||||
case OpCodeAluImm32 op:
|
case OpCode32AluImm op:
|
||||||
context.EmitLdc_I4(op.Imm);
|
context.EmitLdc_I4(op.Imm);
|
||||||
|
|
||||||
if (op.SetFlags && op.IsRotated)
|
if (op.SetFlags && op.IsRotated)
|
||||||
|
@ -182,11 +182,11 @@ namespace ChocolArm64.Instructions
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OpCodeAluRsImm32 op:
|
case OpCode32AluRsImm op:
|
||||||
EmitLoadRmShiftedByImmediate(context, op, setCarry);
|
EmitLoadRmShiftedByImmediate(context, op, setCarry);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OpCodeAluImm8T16 op:
|
case OpCodeT16AluImm8 op:
|
||||||
context.EmitLdc_I4(op.Imm);
|
context.EmitLdc_I4(op.Imm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ namespace ChocolArm64.Instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
//ARM32 helpers.
|
//ARM32 helpers.
|
||||||
private static void EmitLoadRmShiftedByImmediate(ILEmitterCtx context, OpCodeAluRsImm32 op, bool setCarry)
|
private static void EmitLoadRmShiftedByImmediate(ILEmitterCtx context, OpCode32AluRsImm op, bool setCarry)
|
||||||
{
|
{
|
||||||
int shift = op.Imm;
|
int shift = op.Imm;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
public static void B(ILEmitterCtx context)
|
public static void B(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
IOpCodeBImm32 op = (IOpCodeBImm32)context.CurrOp;
|
IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;
|
||||||
|
|
||||||
if (context.CurrBlock.Branch != null)
|
if (context.CurrBlock.Branch != null)
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void Bx(ILEmitterCtx context)
|
public static void Bx(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
IOpCodeBReg32 op = (IOpCodeBReg32)context.CurrOp;
|
IOpCode32BReg op = (IOpCode32BReg)context.CurrOp;
|
||||||
|
|
||||||
context.EmitStoreState();
|
context.EmitStoreState();
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
private static void Blx(ILEmitterCtx context, bool x)
|
private static void Blx(ILEmitterCtx context, bool x)
|
||||||
{
|
{
|
||||||
IOpCodeBImm32 op = (IOpCodeBImm32)context.CurrOp;
|
IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;
|
||||||
|
|
||||||
uint pc = op.GetPc();
|
uint pc = op.GetPc();
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
325
ChocolArm64/Instructions/InstEmitMemory32.cs
Normal file
325
ChocolArm64/Instructions/InstEmitMemory32.cs
Normal 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)
|
||||||
|
{
|
||||||
|
OpCode32MemMult op = (OpCode32MemMult)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)
|
||||||
|
{
|
||||||
|
OpCode32MemMult op = (OpCode32MemMult)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)
|
||||||
|
{
|
||||||
|
OpCode32Mem op = (OpCode32Mem)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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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(OpCode32AluImm));
|
||||||
SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Add, typeof(OpCodeAluRsImm32));
|
SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Add, typeof(OpCode32AluRsImm));
|
||||||
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.B, typeof(OpCodeBImm32));
|
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.B, typeof(OpCode32BImm));
|
||||||
SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Bl, typeof(OpCodeBImm32));
|
SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Bl, typeof(OpCode32BImm));
|
||||||
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Blx, typeof(OpCodeBImm32));
|
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Blx, typeof(OpCode32BImm));
|
||||||
SetA32("<<<<000100101111111111110001xxxx", InstEmit32.Bx, typeof(OpCodeBReg32));
|
SetA32("<<<<000100101111111111110001xxxx", InstEmit32.Bx, typeof(OpCode32BReg));
|
||||||
SetT32( "010001110xxxx000", InstEmit32.Bx, typeof(OpCodeBRegT16));
|
SetT32("010001110xxxx000", InstEmit32.Bx, typeof(OpCodeT16BReg));
|
||||||
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstEmit32.Mov, typeof(OpCodeAluImm32));
|
SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstEmit32.Cmp, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstEmit32.Mov, typeof(OpCodeAluRsImm32));
|
SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstEmit32.Cmp, typeof(OpCode32AluRsImm));
|
||||||
SetT32( "00100xxxxxxxxxxx", InstEmit32.Mov, typeof(OpCodeAluImm8T16));
|
SetA32("<<<<100xx0x1xxxxxxxxxxxxxxxxxxxx", InstEmit32.Ldm, typeof(OpCode32MemMult));
|
||||||
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Sub, typeof(OpCodeAluImm32));
|
SetA32("<<<<010xx0x1xxxxxxxxxxxxxxxxxxxx", InstEmit32.Ldr, typeof(OpCode32MemImm));
|
||||||
SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Sub, typeof(OpCodeAluRsImm32));
|
SetA32("<<<<010xx1x1xxxxxxxxxxxxxxxxxxxx", InstEmit32.Ldrb, typeof(OpCode32MemImm));
|
||||||
|
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(OpCode32AluImm));
|
||||||
|
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstEmit32.Mov, typeof(OpCode32AluRsImm));
|
||||||
|
SetT32("00100xxxxxxxxxxx", InstEmit32.Mov, typeof(OpCodeT16AluImm8));
|
||||||
|
SetA32("<<<<100xx0x0xxxxxxxxxxxxxxxxxxxx", InstEmit32.Stm, typeof(OpCode32MemMult));
|
||||||
|
SetA32("<<<<010xx0x0xxxxxxxxxxxxxxxxxxxx", InstEmit32.Str, typeof(OpCode32MemImm));
|
||||||
|
SetA32("<<<<010xx1x0xxxxxxxxxxxxxxxxxxxx", InstEmit32.Strb, typeof(OpCode32MemImm));
|
||||||
|
SetA32("<<<<000xx1x0xxxxxxxxxxxx1111xxxx", InstEmit32.Strd, typeof(OpCode32MemImm8));
|
||||||
|
SetA32("<<<<000xx1x0xxxxxxxxxxxx1011xxxx", InstEmit32.Strh, typeof(OpCode32MemImm8));
|
||||||
|
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Sub, typeof(OpCode32AluImm));
|
||||||
|
SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Sub, typeof(OpCode32AluRsImm));
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "OpCode Table (AArch64)"
|
#region "OpCode Table (AArch64)"
|
||||||
|
|
|
@ -13,8 +13,6 @@ 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,
|
||||||
X16, X17, X18, X19, X20, X21, X22, X23,
|
X16, X17, X18, X19, X20, X21, X22, X23,
|
||||||
|
@ -25,13 +23,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; }
|
||||||
|
@ -51,10 +52,10 @@ namespace ChocolArm64.State
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (Negative ? (int)PState.N : 0) |
|
return (Negative ? (int)PState.NMask : 0) |
|
||||||
(Zero ? (int)PState.Z : 0) |
|
(Zero ? (int)PState.ZMask : 0) |
|
||||||
(Carry ? (int)PState.C : 0) |
|
(Carry ? (int)PState.CMask : 0) |
|
||||||
(Overflow ? (int)PState.V : 0);
|
(Overflow ? (int)PState.VMask : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +141,7 @@ namespace ChocolArm64.State
|
||||||
|
|
||||||
internal ExecutionMode GetExecutionMode()
|
internal ExecutionMode GetExecutionMode()
|
||||||
{
|
{
|
||||||
if (!IsAarch32)
|
if (!Aarch32)
|
||||||
{
|
{
|
||||||
return ExecutionMode.Aarch64;
|
return ExecutionMode.Aarch64;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,22 +6,19 @@ namespace ChocolArm64.State
|
||||||
enum PState
|
enum PState
|
||||||
{
|
{
|
||||||
TBit = 5,
|
TBit = 5,
|
||||||
|
EBit = 9,
|
||||||
|
|
||||||
VBit = 28,
|
VBit = 28,
|
||||||
CBit = 29,
|
CBit = 29,
|
||||||
ZBit = 30,
|
ZBit = 30,
|
||||||
NBit = 31,
|
NBit = 31,
|
||||||
|
|
||||||
T = 1 << TBit,
|
TMask = 1 << TBit,
|
||||||
|
EMask = 1 << EBit,
|
||||||
|
|
||||||
V = 1 << VBit,
|
VMask = 1 << VBit,
|
||||||
C = 1 << CBit,
|
CMask = 1 << CBit,
|
||||||
Z = 1 << ZBit,
|
ZMask = 1 << ZBit,
|
||||||
N = 1 << NBit,
|
NMask = 1 << NBit
|
||||||
|
|
||||||
Nz = N | Z,
|
|
||||||
Cv = C | V,
|
|
||||||
|
|
||||||
Nzcv = Nz | Cv
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -530,7 +530,15 @@ namespace ChocolArm64.Translation
|
||||||
public void EmitLdflg(int index) => Ldloc(index, IoType.Flag);
|
public void EmitLdflg(int index) => Ldloc(index, IoType.Flag);
|
||||||
public void EmitStflg(int index)
|
public void EmitStflg(int index)
|
||||||
{
|
{
|
||||||
_optOpLastFlagSet = CurrOp;
|
//Set this only if any of the NZCV flag bits were modified.
|
||||||
|
//This is used to ensure that, when emiting a direct IL branch
|
||||||
|
//instruction for compare + branch sequences, we're not expecting
|
||||||
|
//to use comparison values from an old instruction, when in fact
|
||||||
|
//the flags were already overwritten by another instruction further along.
|
||||||
|
if (index >= (int)PState.VBit)
|
||||||
|
{
|
||||||
|
_optOpLastFlagSet = CurrOp;
|
||||||
|
}
|
||||||
|
|
||||||
Stloc(index, IoType.Flag);
|
Stloc(index, IoType.Flag);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue