Initial work on A32 instructions + SVC. No tests yet, hangs in rtld.

This commit is contained in:
riperiperi 2019-12-24 14:53:31 +00:00 committed by Thog
parent bbb86a1f7c
commit 36787d06dd
No known key found for this signature in database
GPG key ID: 0CD291558FAFDBC6
27 changed files with 819 additions and 25 deletions

View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
interface IOpCode32AluBf
{
public int Rd { get; }
public int Rn { get; }
public int Msb { get; }
public int Lsb { get; }
}
}

View file

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
interface IOpCode32AluReg : IOpCode32Alu
{
public int Rm { get; }
}
}

View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
interface IOpCode32AluUx : IOpCode32AluReg
{
public int RotateBits { get; }
public bool Add { get; }
}
}

View file

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32AluBf : OpCode32, IOpCode32AluBf
{
public int Rd { get; private set; }
public int Rn { get; private set; }
public int Msb { get; private set; }
public int Lsb { get; private set; }
public int SourceMask => (int)(0xFFFFFFFF >> (31 - Msb));
public int DestMask => SourceMask << Lsb;
public OpCode32AluBf(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 12) & 0xf;
Rn = (opCode >> 0) & 0xf;
Msb = ((opCode >> 16) & 31);
Lsb = ((opCode >> 17) & 31);
}
}
}

View file

@ -6,7 +6,7 @@
public OpCode32AluImm16(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
int imm12 = opCode & 0xffff;
int imm12 = opCode & 0xfff;
int imm4 = (opCode >> 16) & 0xf;
Immediate = (imm4 << 12) | imm12;

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32AluReg : OpCode32Alu, IOpCode32AluReg
{
public int Rm { get; private set; }
public OpCode32AluReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = (opCode >> 0) & 0xf;
}
}
}

View file

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32AluUmull : OpCode32
{
public int RdLo { get; private set; }
public int RdHi { get; private set; }
public int Rn { get; private set; }
public int Rm { get; private set; }
public bool SetFlags { get; private set; }
public DataOp DataOp { get; private set; }
public OpCode32AluUmull(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
RdLo = (opCode >> 12) & 0xf;
RdHi = (opCode >> 16) & 0xf;
Rm = (opCode >> 8) & 0xf;
Rn = (opCode >> 0) & 0xf;
SetFlags = ((opCode >> 20) & 1) != 0;
DataOp = DataOp.Arithmetic;
}
}
}

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32AluUx : OpCode32AluReg, IOpCode32AluUx
{
public int Rotate { get; private set; }
public int RotateBits => Rotate * 8;
public bool Add => Rn != 15;
public OpCode32AluUx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rotate = (opCode >> 10) & 0x3;
}
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32Exception : OpCode32
{
public int Id { get; private set; }
public OpCode32Exception(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Id = opCode & 0xFFFFFF;
}
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32MemRsImm : OpCode32Mem
{
public int Rm { get; private set; }
public ShiftType ShiftType { get; private set; }
public OpCode32MemRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = (opCode >> 0) & 0xf;
Immediate = (opCode >> 7) & 0x1f;
ShiftType = (ShiftType)((opCode >> 5) & 3);
}
}
}

View file

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32SimdMemMult : OpCode32
{
public int Rn { get; private set; }
public int Vd { get; private set; }
public int RegisterRange
{ get; private set; }
public int Offset { get; private set; }
public int PostOffset { get; private set; }
public bool IsLoad { get; private set; }
public bool DoubleWidth { get; private set; }
public OpCode32SimdMemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rn = (opCode >> 16) & 0xf;
Vd = (opCode >> 12) & 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;
DoubleWidth = (opCode & (1 << 8)) != 0;
RegisterRange = opCode & 0xff;
int regsSize = RegisterRange * 4; // double mode is still measured in single register size
if (!u)
{
Offset -= regsSize;
}
if (u == p)
{
Offset += 4;
}
if (w)
{
PostOffset = u ? regsSize : -regsSize;
}
else
{
PostOffset = 0;
}
IsLoad = isLoad;
}
}
}

View file

@ -601,33 +601,81 @@ namespace ARMeilleure.Decoders
// Base
SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstName.Add, InstEmit32.Add, typeof(OpCode32AluImm));
SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstName.Add, InstEmit32.Add, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<0010000xxxxxxxxxxxxxxxxxxxxx", InstName.And, InstEmit32.And, typeof(OpCode32AluImm));
SetA32("<<<<0000000xxxxxxxxxxxxxxxx0xxxx", InstName.And, InstEmit32.And, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstName.B, InstEmit32.B, typeof(OpCode32BImm));
SetA32("<<<<0111110xxxxxxxxxxxxxx0011111", InstName.Bfc, InstEmit32.Bfc, typeof(OpCode32AluBf));
SetA32("<<<<0111110xxxxxxxxxxxxxx001xxxx", InstName.Bfi, InstEmit32.Bfi, typeof(OpCode32AluBf));
SetA32("<<<<0011110xxxxxxxxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, typeof(OpCode32AluImm));
SetA32("<<<<0001110xxxxxxxxxxxxxxxx0xxxx", InstName.Bic, InstEmit32.Bic, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bl, InstEmit32.Bl, typeof(OpCode32BImm));
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, InstEmit32.Blx, typeof(OpCode32BImm));
SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, typeof(OpCode32BReg));
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, typeof(OpCode32BReg));
SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, InstEmit32.Bx, typeof(OpCodeT16BReg));
SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluImm));
SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<00110111xxxx0000xxxxxxxxxxxx", InstName.Cmn, InstEmit32.Cmn, typeof(OpCode32AluImm));
SetA32("<<<<00010111xxxx0000xxxxxxx0xxxx", InstName.Cmn, InstEmit32.Cmn, typeof(OpCode32AluRsImm));
SetA32("<<<<0010001xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluImm));
SetA32("<<<<0000001xxxxxxxxxxxxxxxx0xxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<100xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, typeof(OpCode32MemMult));
SetA32("<<<<010xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, typeof(OpCode32MemImm));
SetA32("<<<<011xx0x1xxxxxxxxxxxxxxx0xxxx", InstName.Ldr, InstEmit32.Ldr, typeof(OpCode32MemRsImm));
SetA32("<<<<010xx1x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, typeof(OpCode32MemImm));
SetA32("<<<<011xx1x1xxxxxxxxxxxxxxx0xxxx", InstName.Ldrb, InstEmit32.Ldrb, typeof(OpCode32MemRsImm));
SetA32("<<<<000xx1x0xxxxxxxxxxxx1101xxxx", InstName.Ldrd, InstEmit32.Ldrd, typeof(OpCode32MemImm8));
//SetA32("<<<<000xx0x0xxxxxxxx00001101xxxx", InstName.Ldrd, InstEmit32.Ldrd, typeof(OpCode32MemReg)); //??? wip
SetA32("<<<<000xx1x1xxxxxxxxxxxx1011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemImm8));
//SetA32("<<<<000xx0x1xxxxxxxx00001011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemReg)); //??? wip
SetA32("<<<<000xx1x1xxxxxxxxxxxx1101xxxx", InstName.Ldrsb, InstEmit32.Ldrsb, typeof(OpCode32MemImm8));
SetA32("<<<<000xx1x1xxxxxxxxxxxx1111xxxx", InstName.Ldrsh, InstEmit32.Ldrsh, typeof(OpCode32MemImm8));
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluImm));
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluRsImm));
SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluImm16));
SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCodeT16AluImm8));
SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, typeof(OpCode32AluImm16));
SetA32("<<<<0000000xxxxx0000xxxx1001xxxx", InstName.Mul, InstEmit32.Mul, typeof(OpCode32AluReg));
SetA32("<<<<0011111x0000xxxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, typeof(OpCode32AluImm));
SetA32("<<<<0001111x0000xxxxxxxxxxx0xxxx", InstName.Mvn, InstEmit32.Mvn, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<0011100xxxxxxxxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, typeof(OpCode32AluImm));
SetA32("<<<<0001100xxxxxxxxxxxxxxxx0xxxx", InstName.Orr, InstEmit32.Orr, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<0010011xxxxxxxxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluImm));
SetA32("<<<<0000011xxxxxxxxxxxxxxxx0xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<100xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, typeof(OpCode32MemMult));
SetA32("<<<<010xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit32.Str, typeof(OpCode32MemImm));
SetA32("<<<<011xx0x0xxxxxxxxxxxxxxx0xxxx", InstName.Str, InstEmit32.Str, typeof(OpCode32MemRsImm));
SetA32("<<<<010xx1x0xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, typeof(OpCode32MemImm));
SetA32("<<<<011xx1x0xxxxxxxxxxxxxxx0xxxx", InstName.Strb, InstEmit32.Strb, typeof(OpCode32MemRsImm));
SetA32("<<<<000xx1x0xxxxxxxxxxxx1111xxxx", InstName.Strd, InstEmit32.Strd, typeof(OpCode32MemImm8));
//SetA32("<<<<000xx0x0xxxxxxxx00001111xxxx", InstName.Strd, InstEmit32.Strd, typeof(OpCode32MemReg)); //??? wip
SetA32("<<<<000xx1x0xxxxxxxxxxxx1011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemImm8));
//SetA32("<<<<000xx0x0xxxxxxxx00001011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemReg)); //??? wip
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluImm));
SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<1111xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Svc, InstEmit32.Svc, typeof(OpCode32Exception));
SetA32("<<<<00110011xxxx0000xxxxxxxxxxxx", InstName.Teq, InstEmit32.Teq, typeof(OpCode32AluImm));
#endregion
SetA32("<<<<00110001xxxx0000xxxxxxxxxxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluImm));
SetA32("<<<<00010001xxxx0000xxxxxxx0xxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, typeof(OpCode32AluUmull));
SetA32("<<<<01101110xxxxxxxxxx000111xxxx", InstName.Uxtb, InstEmit32.Uxtb, typeof(OpCode32AluUx));
// FP & SIMD (AArch32)
SetA32("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, typeof(OpCode32SimdMemMult));
SetA32("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, typeof(OpCode32SimdMemMult));
SetA32("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, typeof(OpCode32SimdMemMult));
SetA32("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, typeof(OpCode32SimdMemMult));
#endregion
FillFastLookupTable(_instA32FastLookup, _allInstA32);
FillFastLookupTable(_instT32FastLookup, _allInstT32);

View file

@ -46,6 +46,21 @@ namespace ARMeilleure.Instructions
EmitSubsVCheck(context, n, m, res);
}
public static void Cmn(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
Operand n = GetAluN(context);
Operand m = GetAluM(context, setCarry: false);
Operand res = context.Add(n, m);
EmitNZFlagsCheck(context, res);
EmitAddsCCheck(context, n, res);
EmitAddsVCheck(context, n, m, res);
}
public static void Mov(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
@ -80,6 +95,105 @@ namespace ARMeilleure.Instructions
EmitAluStore(context, res);
}
public static void Rsb(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
Operand n = GetAluN(context);
Operand m = GetAluM(context, setCarry: false);
Operand res = context.Subtract(m, n);
if (op.SetFlags)
{
EmitNZFlagsCheck(context, res);
EmitSubsCCheck(context, m, res);
EmitSubsVCheck(context, m, n, res);
}
EmitAluStore(context, res);
}
public static void And(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
Operand n = GetAluN(context);
Operand m = GetAluM(context);
Operand res = context.BitwiseAnd(n, m);
if (op.SetFlags)
{
EmitNZFlagsCheck(context, res);
}
EmitAluStore(context, res);
}
public static void Bic(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
Operand n = GetAluN(context);
Operand m = GetAluM(context);
Operand res = context.BitwiseAnd(n, context.BitwiseNot(m));
if (op.SetFlags)
{
EmitNZFlagsCheck(context, res);
}
EmitAluStore(context, res);
}
public static void Tst(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
Operand n = GetAluN(context);
Operand m = GetAluM(context);
Operand res = context.BitwiseAnd(n, m);
EmitNZFlagsCheck(context, res);
}
public static void Orr(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
Operand n = GetAluN(context);
Operand m = GetAluM(context);
Operand res = context.BitwiseOr(n, m);
if (op.SetFlags)
{
EmitNZFlagsCheck(context, res);
}
EmitAluStore(context, res);
}
public static void Eor(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
Operand n = GetAluN(context);
Operand m = GetAluM(context);
Operand res = context.BitwiseExclusiveOr(n, m);
if (op.SetFlags)
{
EmitNZFlagsCheck(context, res);
}
EmitAluStore(context, res);
}
public static void Teq(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
@ -92,6 +206,100 @@ namespace ARMeilleure.Instructions
EmitNZFlagsCheck(context, res);
}
public static void Uxtb(ArmEmitterContext context)
{
IOpCode32AluUx op = (IOpCode32AluUx)context.CurrOp;
Operand m = GetAluM(context);
Operand res;
if (op.RotateBits == 0)
{
res = m;
}
else
{
Operand rotate = Const(op.RotateBits);
res = context.RotateRight(m, rotate);
}
res = context.ZeroExtend8(OperandType.I32, res);
if (op.Add)
{
res = context.Add(res, GetAluN(context));
}
EmitAluStore(context, res);
}
public static void Movt(ArmEmitterContext context)
{
OpCode32AluImm16 op = (OpCode32AluImm16)context.CurrOp;
Operand d = GetIntOrZR(context, op.Rd);
Operand imm = Const(op.Immediate << 16); //immeditate value as top halfword
Operand res = context.BitwiseAnd(d, Const(0x0000ffff));
res = context.BitwiseOr(res, imm);
EmitAluStore(context, res);
}
public static void Mvn(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
Operand m = GetAluM(context);
Operand res = context.BitwiseNot(m);
if (op.SetFlags)
{
EmitNZFlagsCheck(context, res);
}
EmitAluStore(context, res);
}
public static void Mul(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
Operand n = GetAluN(context);
Operand m = GetAluM(context);
Operand res = context.Multiply(n, m);
if (op.SetFlags)
{
EmitNZFlagsCheck(context, res);
}
EmitAluStore(context, res);
}
public static void Bfc(ArmEmitterContext context)
{
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
Operand d = GetIntOrZR(context, op.Rd);
Operand res = context.BitwiseAnd(d, Const(~op.SourceMask));
SetIntA32(context, op.Rd, res);
}
public static void Bfi(ArmEmitterContext context)
{
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
Operand n = GetIntOrZR(context, op.Rn);
Operand d = GetIntOrZR(context, op.Rd);
Operand part = context.BitwiseAnd(n, Const(op.SourceMask));
Operand res = context.BitwiseAnd(d, Const(~op.SourceMask));
res = context.BitwiseOr(res, part);
SetIntA32(context, op.Rd, res);
}
private static void EmitAluStore(ArmEmitterContext context, Operand value)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;

View file

@ -122,6 +122,8 @@ namespace ARMeilleure.Instructions
case OpCodeT16AluImm8 op: return Const(op.Immediate);
case OpCode32AluReg op: return GetIntA32(context, op.Rm);
// ARM64.
case IOpCodeAluImm op:
{
@ -169,7 +171,7 @@ namespace ARMeilleure.Instructions
}
// ARM32 helpers.
private static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32AluRsImm op, bool setCarry)
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32AluRsImm op, bool setCarry)
{
Operand m = GetIntA32(context, op.Rm);
@ -210,7 +212,7 @@ namespace ARMeilleure.Instructions
return m;
}
private static Operand GetLslC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
public static Operand GetLslC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
{
if ((uint)shift > 32)
{
@ -240,7 +242,7 @@ namespace ARMeilleure.Instructions
}
}
private static Operand GetLsrC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
public static Operand GetLsrC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
{
if ((uint)shift > 32)
{
@ -276,7 +278,7 @@ namespace ARMeilleure.Instructions
return Const(0);
}
private static Operand GetAsrC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
public static Operand GetAsrC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
{
if ((uint)shift >= 32)
{
@ -300,7 +302,7 @@ namespace ARMeilleure.Instructions
}
}
private static Operand GetRorC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
public static Operand GetRorC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
{
shift &= 0x1f;
@ -314,7 +316,7 @@ namespace ARMeilleure.Instructions
return m;
}
private static Operand GetRrxC(ArmEmitterContext context, Operand m, bool setCarry)
public static Operand GetRrxC(ArmEmitterContext context, Operand m, bool setCarry)
{
// Rotate right by 1 with carry.
Operand cIn = context.Copy(GetFlag(PState.CFlag));

View file

@ -0,0 +1,35 @@
using ARMeilleure.Decoders;
using ARMeilleure.Translation;
using System;
using System.Collections.Generic;
using System.Text;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
namespace ARMeilleure.Instructions
{
static partial class InstEmit32
{
public static void Svc(ArmEmitterContext context)
{
EmitExceptionCall(context, NativeInterface.SupervisorCall);
}
private static void EmitExceptionCall(ArmEmitterContext context, _Void_U64_S32 func)
{
OpCode32Exception op = (OpCode32Exception)context.CurrOp;
context.StoreToContext();
context.Call(func, Const(op.Address), Const(op.Id));
context.LoadFromContext();
if (context.CurrBlock.Next == null)
{
context.Return(Const(op.Address + 4));
}
}
}
}

View file

@ -1,4 +1,5 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
@ -20,7 +21,6 @@ namespace ARMeilleure.Instructions
else
{
context.StoreToContext();
context.Return(Const(op.Immediate));
}
}
@ -67,5 +67,28 @@ namespace ARMeilleure.Instructions
InstEmitFlowHelper.EmitCall(context, (ulong)op.Immediate);
}
public static void Blxr(ArmEmitterContext context)
{
IOpCode32BReg op = (IOpCode32BReg)context.CurrOp;
uint pc = op.GetPc();
Operand addr = GetIntA32(context, op.Rm);
Operand bitOne = context.BitwiseAnd(addr, Const(0));
bool isThumb = IsThumb(context.CurrOp);
uint currentPc = isThumb
? op.GetPc() | 1
: op.GetPc() - 4;
SetIntOrSP(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
SetFlag(context, PState.TFlag, bitOne);
addr = context.BitwiseOr(addr, Const(1)); // set call flag
context.Return(addr); // call
}
}
}

View file

@ -47,6 +47,11 @@ namespace ARMeilleure.Instructions
}
}
public static Operand GetVecA32(int regIndex)
{
return Register(regIndex, RegisterType.Vector, OperandType.V128);
}
public static void SetIntA32(ArmEmitterContext context, int regIndex, Operand value)
{
if (regIndex == RegisterAlias.Aarch32Pc)

View file

@ -152,14 +152,15 @@ namespace ARMeilleure.Instructions
OpCode32Mem op = (OpCode32Mem)context.CurrOp;
Operand n = context.Copy(GetIntA32(context, op.Rn));
Operand m = GetMemM(context, setCarry: false);
Operand temp = null;
if (op.Index || op.WBack)
{
temp = op.Add
? context.Add (n, Const(op.Immediate))
: context.Subtract(n, Const(op.Immediate));
? context.Add (n, m)
: context.Subtract(n, m);
}
if (op.WBack)

View file

@ -505,5 +505,65 @@ namespace ARMeilleure.Instructions
SetIntOrZR(context, rt, value);
}
}
// ARM32 helpers.
public static Operand GetMemM(ArmEmitterContext context, bool setCarry = true)
{
switch (context.CurrOp)
{
// ARM32.
case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
case OpCode32Mem op: return Const(op.Immediate);
default: throw InvalidOpCodeType(context.CurrOp);
}
}
private static Exception InvalidOpCodeType(OpCode opCode)
{
return new InvalidOperationException($"Invalid OpCode type \"{opCode?.GetType().Name ?? "null"}\".");
}
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32MemRsImm op, bool setCarry)
{
Operand m = GetIntA32(context, op.Rm);
int shift = op.Immediate;
if (shift == 0)
{
switch (op.ShiftType)
{
case ShiftType.Lsr: shift = 32; break;
case ShiftType.Asr: shift = 32; break;
case ShiftType.Ror: shift = 1; break;
}
}
if (shift != 0)
{
setCarry &= false;
switch (op.ShiftType)
{
case ShiftType.Lsl: m = InstEmitAluHelper.GetLslC(context, m, setCarry, shift); break;
case ShiftType.Lsr: m = InstEmitAluHelper.GetLsrC(context, m, setCarry, shift); break;
case ShiftType.Asr: m = InstEmitAluHelper.GetAsrC(context, m, setCarry, shift); break;
case ShiftType.Ror:
if (op.Immediate != 0)
{
m = InstEmitAluHelper.GetRorC(context, m, setCarry, shift);
}
else
{
m = InstEmitAluHelper.GetRrxC(context, m, setCarry);
}
break;
}
}
return m;
}
}
}

View file

@ -0,0 +1,65 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitAluHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
namespace ARMeilleure.Instructions
{
static partial class InstEmit32
{
public static void Umull(ArmEmitterContext context)
{
OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn));
Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm));
Operand res = context.Multiply(n, m);
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
Operand lo = context.ConvertI64ToI32(res);
if (op.SetFlags)
{
EmitNZFlagsCheck(context, res);
}
EmitGenericStore(context, op.RdHi, op.SetFlags, hi);
EmitGenericStore(context, op.RdLo, op.SetFlags, lo);
}
private static void EmitGenericStore(ArmEmitterContext context, int Rd, bool setFlags, Operand value)
{
if (Rd == RegisterAlias.Aarch32Pc)
{
if (setFlags)
{
// TODO: Load SPSR etc.
Operand isThumb = GetFlag(PState.TFlag);
Operand lblThumb = Label();
context.BranchIfTrue(lblThumb, isThumb);
context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(value, Const(~3))));
context.MarkLabel(lblThumb);
context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(value, Const(~1))));
}
else
{
EmitAluWritePc(context, value);
}
}
else
{
SetIntA32(context, Rd, value);
}
}
}
}

View file

@ -0,0 +1,81 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitMemoryHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
namespace ARMeilleure.Instructions
{
static partial class InstEmit32
{
public static void Vldm(ArmEmitterContext context)
{
OpCode32SimdMemMult op = (OpCode32SimdMemMult)context.CurrOp;
Operand n = GetIntA32(context, op.Rn);
Operand baseAddress = context.Add(n, Const(op.Offset));
bool writesToPc = (op.RegisterRange & (1 << RegisterAlias.Aarch32Pc)) != 0;
bool writeBack = op.PostOffset != 0 && (op.Rn != RegisterAlias.Aarch32Pc || !writesToPc);
if (writeBack)
{
SetIntA32(context, op.Rn, context.Add(n, Const(op.PostOffset)));
}
int range = op.RegisterRange;
int sReg = (op.DoubleWidth) ? (op.Vd << 1) : op.Vd;
int offset = 0;
int size = (op.DoubleWidth) ? DWordSizeLog2 : WordSizeLog2;
int byteSize = 4;
for (int num = 0; num < range; num++, sReg++)
{
Operand address = context.Add(baseAddress, Const(offset));
Operand vec = GetVecA32(sReg >> 2);
EmitLoadSimd(context, address, vec, sReg >> 2, sReg & 3, 2);
offset += byteSize;
}
}
public static void Vstm(ArmEmitterContext context)
{
OpCode32SimdMemMult op = (OpCode32SimdMemMult)context.CurrOp;
Operand n = GetIntA32(context, op.Rn);
Operand baseAddress = context.Add(n, Const(op.Offset));
bool writeBack = op.PostOffset != 0;
if (writeBack)
{
SetIntA32(context, op.Rn, context.Add(n, Const(op.PostOffset)));
}
int offset = 0;
int range = op.RegisterRange;
int sReg = (op.DoubleWidth) ? (op.Vd << 1) : op.Vd;
int size = (op.DoubleWidth) ? DWordSizeLog2 : WordSizeLog2;
int byteSize = 4;
for (int num = 0; num < range; num++, sReg++)
{
Operand address = context.Add(baseAddress, Const(offset));
EmitStoreSimd(context, address, sReg >> 2, sReg & 3, 2);
offset += byteSize;
}
}
}
}

View file

@ -445,9 +445,14 @@ namespace ARMeilleure.Instructions
Zip2_V,
// Base (AArch32)
Bfc,
Bfi,
Blx,
Bx,
Cmp,
Cmn,
Movt,
Mul,
Ldm,
Ldrb,
Ldrd,
@ -455,10 +460,19 @@ namespace ARMeilleure.Instructions
Ldrsb,
Ldrsh,
Mov,
Mvn,
Rsb,
Stm,
Strb,
Strd,
Strh,
Teq
Teq,
Tst,
Umull,
Uxtb,
// FP & SIMD (AArch32)
Vstm,
Vldm
}
}

View file

@ -24,7 +24,7 @@ namespace ARMeilleure.Translation
public bool ShouldRejit()
{
return _rejit && Interlocked.Increment(ref _callCount) == MinCallsForRejit;
return false && _rejit && Interlocked.Increment(ref _callCount) == MinCallsForRejit;
}
}
}

View file

@ -20,15 +20,15 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
public void SvcCall(object sender, InstExceptionEventArgs e)
{
Action<SvcHandler, ExecutionContext> svcFunc = SvcTable.GetSvcFunc(e.Id);
ExecutionContext context = (ExecutionContext)sender;
Action<SvcHandler, ExecutionContext> svcFunc = SvcTable.GetSvcFunc(e.Id, context.IsAarch32);
if (svcFunc == null)
{
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
}
ExecutionContext context = (ExecutionContext)sender;
svcFunc(this, context);
PostSvcHandler();

View file

@ -148,6 +148,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return QueryMemory(infoPtr, position);
}
public KernelResult QueryMemory32(uint infoPtr, uint x1, uint position)
{
return QueryMemory(infoPtr, position);
}
private KernelResult QueryMemory(ulong infoPtr, ulong position)
{
KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position);

View file

@ -240,6 +240,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
OutputDebugString(strPtr, size);
}
public void OutputDebugString32(uint strPtr, uint size)
{
OutputDebugString(strPtr, size);
}
private void OutputDebugString(ulong strPtr, ulong size)
{
string str = MemoryHelper.ReadAsciiString(_process.CpuMemory, (long)strPtr, (long)size);

View file

@ -11,10 +11,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
static class SvcTable
{
private const int SvcFuncMaxArguments = 8;
private const int SvcFuncMaxArguments32 = 4;
private static Dictionary<int, string> _svcFuncs64;
private static Dictionary<int, string> _svcFuncs32;
private static Action<SvcHandler, ExecutionContext>[] _svcTable64;
private static Action<SvcHandler, ExecutionContext>[] _svcTable32;
static SvcTable()
{
@ -78,25 +81,40 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{ 0x7B, nameof(SvcHandler.TerminateProcess64) }
};
_svcFuncs32 = new Dictionary<int, string>
{
{ 0x06, nameof(SvcHandler.QueryMemory32) },
{ 0x27, nameof(SvcHandler.OutputDebugString32) }
};
_svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80];
_svcTable32 = new Action<SvcHandler, ExecutionContext>[0x80];
}
public static Action<SvcHandler, ExecutionContext> GetSvcFunc(int svcId)
public static Action<SvcHandler, ExecutionContext> GetSvcFunc(int svcId, bool aarch32)
{
if (_svcTable64[svcId] != null)
Action<SvcHandler, ExecutionContext>[] table = aarch32 ? _svcTable32 : _svcTable64;
if (table[svcId] != null)
{
return _svcTable64[svcId];
return table[svcId];
}
if (_svcFuncs64.TryGetValue(svcId, out string svcName))
Dictionary<int, string> funcTable = aarch32 ? _svcFuncs32 : _svcFuncs64;
if (funcTable.TryGetValue(svcId, out string svcName))
{
return _svcTable64[svcId] = GenerateMethod(svcName);
return table[svcId] = GenerateMethod(svcName, aarch32);
}
if (aarch32 && _svcFuncs64.TryGetValue(svcId, out string svcName64))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Svc \"{svcName64}\" ({svcId}) does not have a 32-bit call signature defined - fell back to 64-bit.");
return table[svcId] = GenerateMethod(svcName64, aarch32);
}
return null;
}
private static Action<SvcHandler, ExecutionContext> GenerateMethod(string svcName)
private static Action<SvcHandler, ExecutionContext> GenerateMethod(string svcName, bool aarch32)
{
Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(ExecutionContext) };
@ -106,9 +124,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
ParameterInfo[] methodArgs = methodInfo.GetParameters();
if (methodArgs.Length > SvcFuncMaxArguments)
int maxArgs = aarch32 ? SvcFuncMaxArguments32 : SvcFuncMaxArguments;
if (methodArgs.Length > maxArgs)
{
throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is 8.");
throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is {maxArgs}.");
}
ILGenerator generator = method.GetILGenerator();
@ -308,7 +328,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
// Zero out the remaining unused registers.
while (outRegIndex < SvcFuncMaxArguments)
while (outRegIndex < maxArgs)
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, outRegIndex++);