Initial work on A32 instructions + SVC. No tests yet, hangs in rtld.
This commit is contained in:
parent
bbb86a1f7c
commit
36787d06dd
27 changed files with 819 additions and 25 deletions
15
ARMeilleure/Decoders/IOpCode32AluBf.cs
Normal file
15
ARMeilleure/Decoders/IOpCode32AluBf.cs
Normal 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; }
|
||||
}
|
||||
}
|
11
ARMeilleure/Decoders/IOpCode32AluReg.cs
Normal file
11
ARMeilleure/Decoders/IOpCode32AluReg.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32AluReg : IOpCode32Alu
|
||||
{
|
||||
public int Rm { get; }
|
||||
}
|
||||
}
|
12
ARMeilleure/Decoders/IOpCode32AluUx.cs
Normal file
12
ARMeilleure/Decoders/IOpCode32AluUx.cs
Normal 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; }
|
||||
}
|
||||
}
|
28
ARMeilleure/Decoders/OpCode32AluBf.cs
Normal file
28
ARMeilleure/Decoders/OpCode32AluBf.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
16
ARMeilleure/Decoders/OpCode32AluReg.cs
Normal file
16
ARMeilleure/Decoders/OpCode32AluReg.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
28
ARMeilleure/Decoders/OpCode32AluUmull.cs
Normal file
28
ARMeilleure/Decoders/OpCode32AluUmull.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
18
ARMeilleure/Decoders/OpCode32AluUx.cs
Normal file
18
ARMeilleure/Decoders/OpCode32AluUx.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
16
ARMeilleure/Decoders/OpCode32Exception.cs
Normal file
16
ARMeilleure/Decoders/OpCode32Exception.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
19
ARMeilleure/Decoders/OpCode32MemRsImm.cs
Normal file
19
ARMeilleure/Decoders/OpCode32MemRsImm.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
59
ARMeilleure/Decoders/OpCode32SimdMemMult.cs
Normal file
59
ARMeilleure/Decoders/OpCode32SimdMemMult.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
35
ARMeilleure/Instructions/InstEmitException32.cs
Normal file
35
ARMeilleure/Instructions/InstEmitException32.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
65
ARMeilleure/Instructions/InstEmitMul32.cs
Normal file
65
ARMeilleure/Instructions/InstEmitMul32.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
81
ARMeilleure/Instructions/InstEmitSimdMemory32.cs
Normal file
81
ARMeilleure/Instructions/InstEmitSimdMemory32.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++);
|
||||
|
|
Loading…
Add table
Reference in a new issue