Exclusive access instructions, fix to mul, system instructions.
Now gets to a break after SignalProcessWideKey64.
This commit is contained in:
parent
b1ba16a4d4
commit
aed13bcdd4
21 changed files with 814 additions and 23 deletions
11
ARMeilleure/Decoders/IOpCode32MemEx.cs
Normal file
11
ARMeilleure/Decoders/IOpCode32MemEx.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32MemEx : IOpCode32Mem
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ namespace ARMeilleure.Decoders
|
||||||
Rn = (opCode >> 0) & 0xf;
|
Rn = (opCode >> 0) & 0xf;
|
||||||
|
|
||||||
Msb = ((opCode >> 16) & 31);
|
Msb = ((opCode >> 16) & 31);
|
||||||
Lsb = Msb - ((opCode >> 10) & 31);
|
Lsb = ((opCode >> 7) & 31);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
26
ARMeilleure/Decoders/OpCode32AluMla.cs
Normal file
26
ARMeilleure/Decoders/OpCode32AluMla.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32AluMla : OpCode32, IOpCode32AluReg
|
||||||
|
{
|
||||||
|
public int Rn { get; private set; }
|
||||||
|
public int Rm { get; private set; }
|
||||||
|
public int Ra { get; private set; }
|
||||||
|
public int Rd { get; private set; }
|
||||||
|
|
||||||
|
public bool SetFlags { get; private set; }
|
||||||
|
|
||||||
|
public OpCode32AluMla(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rn = (opCode >> 0) & 0xf;
|
||||||
|
Rm = (opCode >> 8) & 0xf;
|
||||||
|
Ra = (opCode >> 12) & 0xf;
|
||||||
|
Rd = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
SetFlags = ((opCode >> 20) & 1) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
ARMeilleure/Decoders/OpCode32MemLdEx.cs
Normal file
15
ARMeilleure/Decoders/OpCode32MemLdEx.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32MemLdEx : OpCode32Mem, IOpCode32MemEx
|
||||||
|
{
|
||||||
|
public int Rd { get; internal set; }
|
||||||
|
public OpCode32MemLdEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = opCode & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
ARMeilleure/Decoders/OpCode32MemStEx.cs
Normal file
17
ARMeilleure/Decoders/OpCode32MemStEx.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32MemStEx : OpCode32Mem, IOpCode32MemEx
|
||||||
|
{
|
||||||
|
public int Rd { get; internal set; }
|
||||||
|
public new int Rt { get; private set; }
|
||||||
|
public OpCode32MemStEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 12) & 0xf;
|
||||||
|
Rt = (opCode >> 0) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
ARMeilleure/Decoders/OpCode32SimdSpecial.cs
Normal file
18
ARMeilleure/Decoders/OpCode32SimdSpecial.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32SimdSpecial : OpCode32
|
||||||
|
{
|
||||||
|
public int Rt { get; private set; }
|
||||||
|
public int Sreg { get; private set; }
|
||||||
|
|
||||||
|
public OpCode32SimdSpecial(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 12) & 0xf;
|
||||||
|
Sreg = (opCode >> 16) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
ARMeilleure/Decoders/OpCode32System.cs
Normal file
28
ARMeilleure/Decoders/OpCode32System.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32System : OpCode32
|
||||||
|
{
|
||||||
|
public int Opc1 { get; internal set; }
|
||||||
|
public int CRn { get; internal set; }
|
||||||
|
public int Rt { get; internal set; }
|
||||||
|
public int Opc2 { get; internal set; }
|
||||||
|
public int CRm { get; internal set; }
|
||||||
|
|
||||||
|
public int Coproc { get; internal set; }
|
||||||
|
|
||||||
|
public OpCode32System(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Opc1 = (opCode >> 21) & 0x7;
|
||||||
|
CRn = (opCode >> 16) & 0xf;
|
||||||
|
Rt = (opCode >> 12) & 0xf;
|
||||||
|
Opc2 = (opCode >> 5) & 0x7;
|
||||||
|
CRm = (opCode >> 0) & 0xf;
|
||||||
|
|
||||||
|
Coproc = (opCode >> 8) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -616,6 +616,7 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, typeof(OpCode32BReg));
|
SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, typeof(OpCode32BReg));
|
||||||
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, typeof(OpCode32BReg));
|
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, typeof(OpCode32BReg));
|
||||||
SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, InstEmit32.Bx, typeof(OpCodeT16BReg));
|
SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, InstEmit32.Bx, typeof(OpCodeT16BReg));
|
||||||
|
SetA32("11110101011111111111000000011111", InstName.Clrex, InstEmit32.Clrex, typeof(OpCode32));
|
||||||
SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, typeof(OpCode32AluReg));
|
SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, typeof(OpCode32AluReg));
|
||||||
SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluImm));
|
SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluRsImm));
|
SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluRsImm));
|
||||||
|
@ -625,6 +626,13 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<0010001xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluImm));
|
SetA32("<<<<0010001xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<0000001xxxxxxxxxxxxxxxx0xxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluRsImm));
|
SetA32("<<<<0000001xxxxxxxxxxxxxxxx0xxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluRsImm));
|
||||||
//RsReg missing
|
//RsReg missing
|
||||||
|
SetA32("<<<<00011001xxxxxxxx110010011111", InstName.Lda, InstEmit32.Lda, typeof(OpCode32MemLdEx));
|
||||||
|
SetA32("<<<<00011101xxxxxxxx110010011111", InstName.Ldab, InstEmit32.Ldab, typeof(OpCode32MemLdEx));
|
||||||
|
SetA32("<<<<00011001xxxxxxxx111010011111", InstName.Ldaex, InstEmit32.Ldaex, typeof(OpCode32MemLdEx));
|
||||||
|
SetA32("<<<<00011101xxxxxxxx111010011111", InstName.Ldaexb,InstEmit32.Ldaexb,typeof(OpCode32MemLdEx));
|
||||||
|
SetA32("<<<<00011011xxxxxxxx111010011111", InstName.Ldaexd,InstEmit32.Ldaexd,typeof(OpCode32MemLdEx));
|
||||||
|
SetA32("<<<<00011111xxxxxxxx111010011111", InstName.Ldaexh,InstEmit32.Ldaexh,typeof(OpCode32MemLdEx));
|
||||||
|
SetA32("<<<<00011111xxxxxxxx110010011111", InstName.Ldah, InstEmit32.Ldah, typeof(OpCode32MemLdEx));
|
||||||
SetA32("<<<<100xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, typeof(OpCode32MemMult));
|
SetA32("<<<<100xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, typeof(OpCode32MemMult));
|
||||||
SetA32("<<<<010xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, typeof(OpCode32MemImm));
|
SetA32("<<<<010xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, typeof(OpCode32MemImm));
|
||||||
SetA32("<<<<011xx0x1xxxxxxxxxxxxxxx0xxxx", InstName.Ldr, InstEmit32.Ldr, typeof(OpCode32MemRsImm));
|
SetA32("<<<<011xx0x1xxxxxxxxxxxxxxx0xxxx", InstName.Ldr, InstEmit32.Ldr, typeof(OpCode32MemRsImm));
|
||||||
|
@ -632,16 +640,23 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<011xx1x1xxxxxxxxxxxxxxx0xxxx", InstName.Ldrb, InstEmit32.Ldrb, typeof(OpCode32MemRsImm));
|
SetA32("<<<<011xx1x1xxxxxxxxxxxxxxx0xxxx", InstName.Ldrb, InstEmit32.Ldrb, typeof(OpCode32MemRsImm));
|
||||||
SetA32("<<<<000xx1x0xxxxxxxxxxxx1101xxxx", InstName.Ldrd, InstEmit32.Ldrd, typeof(OpCode32MemImm8));
|
SetA32("<<<<000xx1x0xxxxxxxxxxxx1101xxxx", InstName.Ldrd, InstEmit32.Ldrd, typeof(OpCode32MemImm8));
|
||||||
//SetA32("<<<<000xx0x0xxxxxxxx00001101xxxx", InstName.Ldrd, InstEmit32.Ldrd, typeof(OpCode32MemReg)); //??? wip
|
//SetA32("<<<<000xx0x0xxxxxxxx00001101xxxx", InstName.Ldrd, InstEmit32.Ldrd, typeof(OpCode32MemReg)); //??? wip
|
||||||
|
SetA32("<<<<00011001xxxxxxxx111110011111", InstName.Ldrex, InstEmit32.Ldrex, typeof(OpCode32MemLdEx));
|
||||||
|
SetA32("<<<<00011101xxxxxxxx111110011111", InstName.Ldrexb,InstEmit32.Ldrexb,typeof(OpCode32MemLdEx));
|
||||||
|
SetA32("<<<<00011011xxxxxxxx111110011111", InstName.Ldrexd,InstEmit32.Ldrexd,typeof(OpCode32MemLdEx));
|
||||||
|
SetA32("<<<<00011111xxxxxxxx111110011111", InstName.Ldrexh,InstEmit32.Ldrexh,typeof(OpCode32MemLdEx));
|
||||||
SetA32("<<<<000xx1x1xxxxxxxxxxxx1011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemImm8));
|
SetA32("<<<<000xx1x1xxxxxxxxxxxx1011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemImm8));
|
||||||
//SetA32("<<<<000xx0x1xxxxxxxx00001011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemReg)); //??? wip
|
//SetA32("<<<<000xx0x1xxxxxxxx00001011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemReg)); //??? wip
|
||||||
SetA32("<<<<000xx1x1xxxxxxxxxxxx1101xxxx", InstName.Ldrsb, InstEmit32.Ldrsb, typeof(OpCode32MemImm8));
|
SetA32("<<<<000xx1x1xxxxxxxxxxxx1101xxxx", InstName.Ldrsb, InstEmit32.Ldrsb, typeof(OpCode32MemImm8));
|
||||||
SetA32("<<<<000xx1x1xxxxxxxxxxxx1111xxxx", InstName.Ldrsh, InstEmit32.Ldrsh, typeof(OpCode32MemImm8));
|
SetA32("<<<<000xx1x1xxxxxxxxxxxx1111xxxx", InstName.Ldrsh, InstEmit32.Ldrsh, typeof(OpCode32MemImm8));
|
||||||
|
SetA32("<<<<1110xxx0xxxxxxxx111xxxx1xxxx", InstName.Mcr, InstEmit32.Mcr, typeof(OpCode32System));
|
||||||
|
SetA32("<<<<0000001xxxxxxxxxxxxx1001xxxx", InstName.Mla, InstEmit32.Mla, typeof(OpCode32AluMla));
|
||||||
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluImm));
|
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluRsImm));
|
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluRsImm));
|
||||||
SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluImm16));
|
SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluImm16));
|
||||||
SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCodeT16AluImm8));
|
SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCodeT16AluImm8));
|
||||||
SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, typeof(OpCode32AluImm16));
|
SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, typeof(OpCode32AluImm16));
|
||||||
SetA32("<<<<0000000xxxxx0000xxxx1001xxxx", InstName.Mul, InstEmit32.Mul, typeof(OpCode32AluReg));
|
SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, typeof(OpCode32System));
|
||||||
|
SetA32("<<<<0000000xxxxx0000xxxx1001xxxx", InstName.Mul, InstEmit32.Mul, typeof(OpCode32AluMla));
|
||||||
SetA32("<<<<0011111x0000xxxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, typeof(OpCode32AluImm));
|
SetA32("<<<<0011111x0000xxxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<0001111x0000xxxxxxxxxxx0xxxx", InstName.Mvn, InstEmit32.Mvn, typeof(OpCode32AluRsImm));
|
SetA32("<<<<0001111x0000xxxxxxxxxxx0xxxx", InstName.Mvn, InstEmit32.Mvn, typeof(OpCode32AluRsImm));
|
||||||
//RsReg missing
|
//RsReg missing
|
||||||
|
@ -651,6 +666,13 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<0010011xxxxxxxxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluImm));
|
SetA32("<<<<0010011xxxxxxxxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<0000011xxxxxxxxxxxxxxxx0xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsImm));
|
SetA32("<<<<0000011xxxxxxxxxxxxxxxx0xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsImm));
|
||||||
//RsReg missing
|
//RsReg missing
|
||||||
|
SetA32("<<<<00011000xxxx111111001001xxxx", InstName.Stl, InstEmit32.Stl, typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011100xxxx111111001001xxxx", InstName.Stlb, InstEmit32.Stlb, typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011000xxxxxxxx11101001xxxx", InstName.Stlex, InstEmit32.Stlex, typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011100xxxxxxxx11101001xxxx", InstName.Stlexb,InstEmit32.Stlexb,typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011010xxxxxxxx11101001xxxx", InstName.Stlexd,InstEmit32.Stlexd,typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011110xxxxxxxx11101001xxxx", InstName.Stlexh,InstEmit32.Stlexh,typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011110xxxx111111001001xxxx", InstName.Stlh, InstEmit32.Stlh, typeof(OpCode32MemStEx));
|
||||||
SetA32("<<<<100xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, typeof(OpCode32MemMult));
|
SetA32("<<<<100xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, typeof(OpCode32MemMult));
|
||||||
SetA32("<<<<010xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit32.Str, typeof(OpCode32MemImm));
|
SetA32("<<<<010xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit32.Str, typeof(OpCode32MemImm));
|
||||||
SetA32("<<<<011xx0x0xxxxxxxxxxxxxxx0xxxx", InstName.Str, InstEmit32.Str, typeof(OpCode32MemRsImm));
|
SetA32("<<<<011xx0x0xxxxxxxxxxxxxxx0xxxx", InstName.Str, InstEmit32.Str, typeof(OpCode32MemRsImm));
|
||||||
|
@ -658,6 +680,11 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<011xx1x0xxxxxxxxxxxxxxx0xxxx", InstName.Strb, InstEmit32.Strb, typeof(OpCode32MemRsImm));
|
SetA32("<<<<011xx1x0xxxxxxxxxxxxxxx0xxxx", InstName.Strb, InstEmit32.Strb, typeof(OpCode32MemRsImm));
|
||||||
SetA32("<<<<000xx1x0xxxxxxxxxxxx1111xxxx", InstName.Strd, InstEmit32.Strd, typeof(OpCode32MemImm8));
|
SetA32("<<<<000xx1x0xxxxxxxxxxxx1111xxxx", InstName.Strd, InstEmit32.Strd, typeof(OpCode32MemImm8));
|
||||||
//SetA32("<<<<000xx0x0xxxxxxxx00001111xxxx", InstName.Strd, InstEmit32.Strd, typeof(OpCode32MemReg)); //??? wip
|
//SetA32("<<<<000xx0x0xxxxxxxx00001111xxxx", InstName.Strd, InstEmit32.Strd, typeof(OpCode32MemReg)); //??? wip
|
||||||
|
SetA32("<<<<00011000xxxxxxxx11111001xxxx", InstName.Strex, InstEmit32.Strex, typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011100xxxxxxxx11111001xxxx", InstName.Strexb,InstEmit32.Strexb,typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011010xxxxxxxx11111001xxxx", InstName.Strexd,InstEmit32.Strexd,typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011110xxxxxxxx11111001xxxx", InstName.Strexh,InstEmit32.Strexh,typeof(OpCode32MemStEx));
|
||||||
|
SetA32("<<<<00011110xxxx111111001001xxxx", InstName.Stlh, InstEmit32.Stlh, typeof(OpCode32MemStEx));
|
||||||
SetA32("<<<<000xx1x0xxxxxxxxxxxx1011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemImm8));
|
SetA32("<<<<000xx1x0xxxxxxxxxxxx1011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemImm8));
|
||||||
//SetA32("<<<<000xx0x0xxxxxxxx00001011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemReg)); //??? wip
|
//SetA32("<<<<000xx0x0xxxxxxxx00001011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemReg)); //??? wip
|
||||||
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluImm));
|
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluImm));
|
||||||
|
@ -668,12 +695,16 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<00110001xxxx0000xxxxxxxxxxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluImm));
|
SetA32("<<<<00110001xxxx0000xxxxxxxxxxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<00010001xxxx0000xxxxxxx0xxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluRsImm));
|
SetA32("<<<<00010001xxxx0000xxxxxxx0xxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluRsImm));
|
||||||
//RsReg missing
|
//RsReg missing
|
||||||
|
SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx, InstEmit32.Ubfx, typeof(OpCode32AluBf));
|
||||||
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, typeof(OpCode32AluUmull));
|
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, typeof(OpCode32AluUmull));
|
||||||
SetA32("<<<<01101110xxxxxxxxxx000111xxxx", InstName.Uxtb, InstEmit32.Uxtb, typeof(OpCode32AluUx));
|
SetA32("<<<<01101110xxxxxxxxxx000111xxxx", InstName.Uxtb, InstEmit32.Uxtb, typeof(OpCode32AluUx));
|
||||||
|
SetA32("<<<<011011111111xxxxxx000111xxxx", InstName.Uxth, InstEmit32.Uxth, typeof(OpCode32AluUx));
|
||||||
|
|
||||||
// FP & SIMD (AArch32)
|
// FP & SIMD (AArch32)
|
||||||
SetA32("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, typeof(OpCode32SimdMemMult));
|
SetA32("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, typeof(OpCode32SimdMemMult));
|
||||||
SetA32("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, typeof(OpCode32SimdMemMult));
|
SetA32("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, typeof(OpCode32SimdMemMult));
|
||||||
|
SetA32("<<<<11101111xxxxxxxx101000010000", InstName.Vmrs, InstEmit32.Vmrs, typeof(OpCode32SimdSpecial));
|
||||||
|
SetA32("<<<<11101110xxxxxxxx101000010000", InstName.Vmsr, InstEmit32.Vmsr, typeof(OpCode32SimdSpecial));
|
||||||
SetA32("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, typeof(OpCode32SimdMemMult));
|
SetA32("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, typeof(OpCode32SimdMemMult));
|
||||||
SetA32("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, typeof(OpCode32SimdMemMult));
|
SetA32("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, typeof(OpCode32SimdMemMult));
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace ARMeilleure.Instructions
|
||||||
delegate ushort _U16_F32(float a1);
|
delegate ushort _U16_F32(float a1);
|
||||||
delegate ushort _U16_U64(ulong a1);
|
delegate ushort _U16_U64(ulong a1);
|
||||||
|
|
||||||
|
delegate uint _U32();
|
||||||
delegate uint _U32_F32(float a1);
|
delegate uint _U32_F32(float a1);
|
||||||
delegate uint _U32_F64(double a1);
|
delegate uint _U32_F64(double a1);
|
||||||
delegate uint _U32_U32(uint a1);
|
delegate uint _U32_U32(uint a1);
|
||||||
|
@ -74,6 +75,7 @@ namespace ARMeilleure.Instructions
|
||||||
delegate V128 _V128_V128_V128_V128(V128 a1, V128 a2, V128 a3);
|
delegate V128 _V128_V128_V128_V128(V128 a1, V128 a2, V128 a3);
|
||||||
|
|
||||||
delegate void _Void();
|
delegate void _Void();
|
||||||
|
delegate void _Void_U32(uint a1);
|
||||||
delegate void _Void_U64(ulong a1);
|
delegate void _Void_U64(ulong a1);
|
||||||
delegate void _Void_U64_S32(ulong a1, int a2);
|
delegate void _Void_U64_S32(ulong a1, int a2);
|
||||||
delegate void _Void_U64_U16(ulong a1, ushort a2);
|
delegate void _Void_U64_U16(ulong a1, ushort a2);
|
||||||
|
|
|
@ -243,6 +243,51 @@ namespace ARMeilleure.Instructions
|
||||||
EmitAluStore(context, res);
|
EmitAluStore(context, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Uxth(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.ZeroExtend16(OperandType.I32, res);
|
||||||
|
|
||||||
|
if (op.Add)
|
||||||
|
{
|
||||||
|
res = context.Add(res, GetAluN(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitAluStore(context, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Mla(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetAluN(context);
|
||||||
|
Operand m = GetAluM(context);
|
||||||
|
Operand a = GetIntA32(context, op.Ra);
|
||||||
|
|
||||||
|
Operand res = context.Add(context.Multiply(n, m), a);
|
||||||
|
|
||||||
|
if (op.SetFlags)
|
||||||
|
{
|
||||||
|
EmitNZFlagsCheck(context, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitAluStore(context, res);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Movt(ArmEmitterContext context)
|
public static void Movt(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluImm16 op = (OpCode32AluImm16)context.CurrOp;
|
OpCode32AluImm16 op = (OpCode32AluImm16)context.CurrOp;
|
||||||
|
@ -311,6 +356,19 @@ namespace ARMeilleure.Instructions
|
||||||
SetIntA32(context, op.Rd, res);
|
SetIntA32(context, op.Rd, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Ubfx(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
|
||||||
|
|
||||||
|
var msb = op.Lsb + op.Msb; //for this instruction, the msb is actually a width
|
||||||
|
var mask = (int)(0xFFFFFFFF >> (31 - msb)) << op.Lsb;
|
||||||
|
|
||||||
|
Operand n = GetIntOrZR(context, op.Rn);
|
||||||
|
Operand res = context.ShiftRightUI(context.BitwiseAnd(n, Const(mask)), Const(op.Lsb));
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rd, res);
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitAluStore(ArmEmitterContext context, Operand value)
|
private static void EmitAluStore(ArmEmitterContext context, Operand value)
|
||||||
{
|
{
|
||||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
|
|
|
@ -122,7 +122,7 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
case OpCodeT16AluImm8 op: return Const(op.Immediate);
|
case OpCodeT16AluImm8 op: return Const(op.Immediate);
|
||||||
|
|
||||||
case OpCode32AluReg op: return GetIntA32(context, op.Rm);
|
case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
|
||||||
|
|
||||||
// ARM64.
|
// ARM64.
|
||||||
case IOpCodeAluImm op:
|
case IOpCodeAluImm op:
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace ARMeilleure.Instructions
|
||||||
private const int HWordSizeLog2 = 1;
|
private const int HWordSizeLog2 = 1;
|
||||||
private const int WordSizeLog2 = 2;
|
private const int WordSizeLog2 = 2;
|
||||||
private const int DWordSizeLog2 = 3;
|
private const int DWordSizeLog2 = 3;
|
||||||
|
private const int QWordSizeLog2 = 4;
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
enum AccessType
|
enum AccessType
|
||||||
|
@ -23,6 +24,8 @@ namespace ARMeilleure.Instructions
|
||||||
Store = 0,
|
Store = 0,
|
||||||
Signed = 1,
|
Signed = 1,
|
||||||
Load = 2,
|
Load = 2,
|
||||||
|
Ordered = 4,
|
||||||
|
Exclusive = 8,
|
||||||
|
|
||||||
LoadZx = Load,
|
LoadZx = Load,
|
||||||
LoadSx = Load | Signed,
|
LoadSx = Load | Signed,
|
||||||
|
|
312
ARMeilleure/Instructions/InstEmitMemoryEx32.cs
Normal file
312
ARMeilleure/Instructions/InstEmitMemoryEx32.cs
Normal file
|
@ -0,0 +1,312 @@
|
||||||
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using ARMeilleure.Translation;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using ARMeilleure.Instructions;
|
||||||
|
|
||||||
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
|
using static ARMeilleure.Instructions.InstEmitMemoryHelper;
|
||||||
|
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||||
|
using ARMeilleure.Decoders;
|
||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Instructions
|
||||||
|
{
|
||||||
|
static partial class InstEmit32
|
||||||
|
{
|
||||||
|
public static void Clrex(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
context.Call(new _Void(NativeInterface.ClearExclusive));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldrex(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldrexb(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldrexd(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldrexh(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive);
|
||||||
|
}
|
||||||
|
public static void Lda(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldab(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldaex(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldaexb(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldaexd(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldaexh(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ldah(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stores
|
||||||
|
|
||||||
|
public static void Strex(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, WordSizeLog2, AccessType.Store | AccessType.Exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Strexb(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.Store | AccessType.Exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Strexd(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, DWordSizeLog2, AccessType.Store | AccessType.Exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Strexh(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Exclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stl(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, WordSizeLog2, AccessType.Store | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stlb(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.Store | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stlex(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, WordSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stlexb(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stlexd(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, DWordSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stlexh(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stlh(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitExLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
|
||||||
|
{
|
||||||
|
IOpCode32MemEx op = (IOpCode32MemEx)context.CurrOp;
|
||||||
|
|
||||||
|
Operand address = context.Copy(GetIntA32(context, op.Rn));
|
||||||
|
|
||||||
|
var exclusive = (accType & AccessType.Exclusive) != 0;
|
||||||
|
var ordered = (accType & AccessType.Ordered) != 0;
|
||||||
|
|
||||||
|
if (ordered)
|
||||||
|
{
|
||||||
|
EmitBarrier(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((accType & AccessType.Load) != 0)
|
||||||
|
{
|
||||||
|
if (size == DWordSizeLog2)
|
||||||
|
{
|
||||||
|
// keep loads atomic - make the call to get the whole region and then decompose it into parts
|
||||||
|
// for the registers.
|
||||||
|
|
||||||
|
Operand value = EmitExLoad(context, address, exclusive, size);
|
||||||
|
|
||||||
|
Operand valueLow = context.ConvertI64ToI32(value);
|
||||||
|
|
||||||
|
valueLow = context.ZeroExtend32(OperandType.I64, valueLow);
|
||||||
|
|
||||||
|
Operand valueHigh = context.ShiftRightUI(value, Const(32));
|
||||||
|
|
||||||
|
Operand lblBigEndian = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rt, valueLow);
|
||||||
|
SetIntA32(context, op.Rt | 1, valueHigh);
|
||||||
|
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblBigEndian);
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rt | 1, valueLow);
|
||||||
|
SetIntA32(context, op.Rt, valueHigh);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetIntA32(context, op.Rt, EmitExLoad(context, address, exclusive, size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand s = null;
|
||||||
|
|
||||||
|
if (size == DWordSizeLog2)
|
||||||
|
{
|
||||||
|
//split the result into 2 words (based on endianness)
|
||||||
|
|
||||||
|
Operand lo = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt));
|
||||||
|
Operand hi = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt | 1));
|
||||||
|
Operand toStore = Local(OperandType.I64);
|
||||||
|
|
||||||
|
Operand lblBigEndian = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
||||||
|
|
||||||
|
Operand leResult = context.BitwiseOr(lo, context.ShiftLeft(hi, Const(32)));
|
||||||
|
Operand leS = EmitExStore(context, address, leResult, true, size);
|
||||||
|
if (exclusive) SetIntA32(context, op.Rd, leS);
|
||||||
|
|
||||||
|
context.Branch(lblEnd);
|
||||||
|
|
||||||
|
context.MarkLabel(lblBigEndian);
|
||||||
|
|
||||||
|
Operand beResult = context.BitwiseOr(hi, context.ShiftLeft(lo, Const(32)));
|
||||||
|
Operand beS = EmitExStore(context, address, beResult, true, size);
|
||||||
|
if (exclusive) SetIntA32(context, op.Rd, beS);
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
s = EmitExStore(context, address, context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt)), true, size);
|
||||||
|
// This is only needed for exclusive stores. The function returns 0
|
||||||
|
// when the store is successful, and 1 otherwise.
|
||||||
|
if (exclusive) SetIntA32(context, op.Rd, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitExLoad(
|
||||||
|
ArmEmitterContext context,
|
||||||
|
Operand address,
|
||||||
|
bool exclusive,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
Delegate fallbackMethodDlg = null;
|
||||||
|
|
||||||
|
if (exclusive)
|
||||||
|
{
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case 0: fallbackMethodDlg = new _U8_U64(NativeInterface.ReadByteExclusive); break;
|
||||||
|
case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16Exclusive); break;
|
||||||
|
case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32Exclusive); break;
|
||||||
|
case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64Exclusive); break;
|
||||||
|
case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128Exclusive); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case 0: fallbackMethodDlg = new _U8_U64(NativeInterface.ReadByte); break;
|
||||||
|
case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16); break;
|
||||||
|
case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32); break;
|
||||||
|
case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64); break;
|
||||||
|
case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Call(fallbackMethodDlg, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitExStore(
|
||||||
|
ArmEmitterContext context,
|
||||||
|
Operand address,
|
||||||
|
Operand value,
|
||||||
|
bool exclusive,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
if (size < 3)
|
||||||
|
{
|
||||||
|
value = context.ConvertI64ToI32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Delegate fallbackMethodDlg = null;
|
||||||
|
|
||||||
|
if (exclusive)
|
||||||
|
{
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case 0: fallbackMethodDlg = new _S32_U64_U8(NativeInterface.WriteByteExclusive); break;
|
||||||
|
case 1: fallbackMethodDlg = new _S32_U64_U16(NativeInterface.WriteUInt16Exclusive); break;
|
||||||
|
case 2: fallbackMethodDlg = new _S32_U64_U32(NativeInterface.WriteUInt32Exclusive); break;
|
||||||
|
case 3: fallbackMethodDlg = new _S32_U64_U64(NativeInterface.WriteUInt64Exclusive); break;
|
||||||
|
case 4: fallbackMethodDlg = new _S32_U64_V128(NativeInterface.WriteVector128Exclusive); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Call(fallbackMethodDlg, address, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case 0: fallbackMethodDlg = new _Void_U64_U8(NativeInterface.WriteByte); break;
|
||||||
|
case 1: fallbackMethodDlg = new _Void_U64_U16(NativeInterface.WriteUInt16); break;
|
||||||
|
case 2: fallbackMethodDlg = new _Void_U64_U32(NativeInterface.WriteUInt32); break;
|
||||||
|
case 3: fallbackMethodDlg = new _Void_U64_U64(NativeInterface.WriteUInt64); break;
|
||||||
|
case 4: fallbackMethodDlg = new _Void_U64_V128(NativeInterface.WriteVector128); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Call(fallbackMethodDlg, address, value);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitBarrier(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
// Note: This barrier is most likely not necessary, and probably
|
||||||
|
// doesn't make any difference since we need to do a ton of stuff
|
||||||
|
// (software MMU emulation) to read or write anything anyway.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
177
ARMeilleure/Instructions/InstEmitSystem32.cs
Normal file
177
ARMeilleure/Instructions/InstEmitSystem32.cs
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
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 Vmrs(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
var op = (OpCode32SimdSpecial)context.CurrOp;
|
||||||
|
|
||||||
|
if (op.Rt == 15 && op.Sreg == 0b0001)
|
||||||
|
{
|
||||||
|
//special behavior: copy NZCV flags into APSR
|
||||||
|
EmitSetNzcv(context, context.Call(new _U32(NativeInterface.GetFpscr)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Delegate dlg;
|
||||||
|
switch (op.Sreg)
|
||||||
|
{
|
||||||
|
case 0b0000: //FPSID
|
||||||
|
throw new NotImplementedException("Supervisor Only");
|
||||||
|
case 0b0001: //FPSCR
|
||||||
|
dlg = new _U32(NativeInterface.GetFpscr); break;
|
||||||
|
case 0b0101: //MVFR2
|
||||||
|
throw new NotImplementedException("MVFR2");
|
||||||
|
case 0b0110: //MVFR1
|
||||||
|
throw new NotImplementedException("MVFR1");
|
||||||
|
case 0b0111: //MVFR0
|
||||||
|
throw new NotImplementedException("MVFR0");
|
||||||
|
case 0b1000: //FPEXC
|
||||||
|
throw new NotImplementedException("Supervisor Only");
|
||||||
|
default: throw new NotImplementedException($"Unknown VMRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rt, context.Call(dlg));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Vmsr(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
var op = (OpCode32SimdSpecial)context.CurrOp;
|
||||||
|
|
||||||
|
Delegate dlg;
|
||||||
|
switch (op.Sreg)
|
||||||
|
{
|
||||||
|
case 0b0000: //FPSID
|
||||||
|
throw new NotImplementedException("Supervisor Only");
|
||||||
|
case 0b0001: //FPSCR
|
||||||
|
dlg = new _Void_U32(NativeInterface.SetFpscr); break;
|
||||||
|
case 0b0101: //MVFR2
|
||||||
|
throw new Exception("MVFR2");
|
||||||
|
case 0b0110: //MVFR1
|
||||||
|
throw new Exception("MVFR1");
|
||||||
|
case 0b0111: //MVFR0
|
||||||
|
throw new Exception("MVFR0");
|
||||||
|
case 0b1000: //FPEXC
|
||||||
|
throw new NotImplementedException("Supervisor Only");
|
||||||
|
default: throw new NotImplementedException($"Unknown VMSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Call(dlg, GetIntA32(context, op.Rt));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Mrc(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
var op = (OpCode32System)context.CurrOp;
|
||||||
|
|
||||||
|
if (op.Coproc != 15)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Unknown MRC Coprocessor ID 0x{op.Coproc:X16} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.Opc1 != 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Unknown MRC Opc1 0x{op.Opc1:X16} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Delegate dlg;
|
||||||
|
switch (op.CRn)
|
||||||
|
{
|
||||||
|
case 13: // Process and Thread Info
|
||||||
|
if (op.CRm != 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
switch (op.Opc2)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
dlg = new _U32(NativeInterface.GetTpidrEl032); break;
|
||||||
|
case 3:
|
||||||
|
dlg = new _U32(NativeInterface.GetTpidr32); break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.Rt == 15)
|
||||||
|
{
|
||||||
|
//special behavior: copy NZCV flags into APSR
|
||||||
|
EmitSetNzcv(context, context.Call(dlg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetIntA32(context, op.Rt, context.Call(dlg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Mcr(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
var op = (OpCode32System)context.CurrOp;
|
||||||
|
|
||||||
|
if (op.Coproc != 15)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Unknown MRC Coprocessor ID 0x{op.Coproc:X16} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.Opc1 != 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Unknown MRC Opc1 0x{op.Opc1:X16} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Delegate dlg;
|
||||||
|
switch (op.CRn)
|
||||||
|
{
|
||||||
|
case 13: // Process and Thread Info
|
||||||
|
if (op.CRm != 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
switch (op.Opc2)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
dlg = new _Void_U32(NativeInterface.SetTpidrEl032); break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Call(dlg, GetIntA32(context, op.Rt));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitSetNzcv(ArmEmitterContext context, Operand t)
|
||||||
|
{
|
||||||
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
|
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
|
||||||
|
v = context.BitwiseAnd(v, Const(1));
|
||||||
|
|
||||||
|
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
|
||||||
|
c = context.BitwiseAnd(c, Const(1));
|
||||||
|
|
||||||
|
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
|
||||||
|
z = context.BitwiseAnd(z, Const(1));
|
||||||
|
|
||||||
|
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
|
||||||
|
n = context.BitwiseAnd(n, Const(1));
|
||||||
|
|
||||||
|
SetFlag(context, PState.VFlag, v);
|
||||||
|
SetFlag(context, PState.CFlag, c);
|
||||||
|
SetFlag(context, PState.ZFlag, z);
|
||||||
|
SetFlag(context, PState.NFlag, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -453,26 +453,55 @@ namespace ARMeilleure.Instructions
|
||||||
Cmn,
|
Cmn,
|
||||||
Movt,
|
Movt,
|
||||||
Mul,
|
Mul,
|
||||||
|
Lda,
|
||||||
|
Ldab,
|
||||||
|
Ldaex,
|
||||||
|
Ldaexb,
|
||||||
|
Ldaexd,
|
||||||
|
Ldaexh,
|
||||||
|
Ldah,
|
||||||
Ldm,
|
Ldm,
|
||||||
Ldrb,
|
Ldrb,
|
||||||
Ldrd,
|
Ldrd,
|
||||||
|
Ldrex,
|
||||||
|
Ldrexb,
|
||||||
|
Ldrexd,
|
||||||
|
Ldrexh,
|
||||||
Ldrh,
|
Ldrh,
|
||||||
Ldrsb,
|
Ldrsb,
|
||||||
Ldrsh,
|
Ldrsh,
|
||||||
|
Mcr,
|
||||||
|
Mla,
|
||||||
Mov,
|
Mov,
|
||||||
|
Mrc,
|
||||||
Mvn,
|
Mvn,
|
||||||
Rsb,
|
Rsb,
|
||||||
|
Stl,
|
||||||
|
Stlb,
|
||||||
|
Stlex,
|
||||||
|
Stlexb,
|
||||||
|
Stlexd,
|
||||||
|
Stlexh,
|
||||||
|
Stlh,
|
||||||
Stm,
|
Stm,
|
||||||
Strb,
|
Strb,
|
||||||
Strd,
|
Strd,
|
||||||
|
Strex,
|
||||||
|
Strexb,
|
||||||
|
Strexd,
|
||||||
|
Strexh,
|
||||||
Strh,
|
Strh,
|
||||||
Teq,
|
Teq,
|
||||||
Tst,
|
Tst,
|
||||||
|
Ubfx,
|
||||||
Umull,
|
Umull,
|
||||||
Uxtb,
|
Uxtb,
|
||||||
|
Uxth,
|
||||||
|
|
||||||
// FP & SIMD (AArch32)
|
// FP & SIMD (AArch32)
|
||||||
Vstm,
|
Vstm,
|
||||||
|
Vmrs,
|
||||||
|
Vmsr,
|
||||||
Vldm
|
Vldm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,16 +87,32 @@ namespace ARMeilleure.Instructions
|
||||||
return (ulong)GetContext().Fpsr;
|
return (ulong)GetContext().Fpsr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static uint GetFpscr()
|
||||||
|
{
|
||||||
|
ExecutionContext context = GetContext();
|
||||||
|
return (uint)(context.Fpsr & FPSR.A32Mask) | (uint)(context.Fpcr & FPCR.A32Mask);
|
||||||
|
}
|
||||||
|
|
||||||
public static ulong GetTpidrEl0()
|
public static ulong GetTpidrEl0()
|
||||||
{
|
{
|
||||||
return (ulong)GetContext().TpidrEl0;
|
return (ulong)GetContext().TpidrEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static uint GetTpidrEl032()
|
||||||
|
{
|
||||||
|
return (uint)GetContext().TpidrEl0;
|
||||||
|
}
|
||||||
|
|
||||||
public static ulong GetTpidr()
|
public static ulong GetTpidr()
|
||||||
{
|
{
|
||||||
return (ulong)GetContext().Tpidr;
|
return (ulong)GetContext().Tpidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static uint GetTpidr32()
|
||||||
|
{
|
||||||
|
return (uint)GetContext().Tpidr;
|
||||||
|
}
|
||||||
|
|
||||||
public static ulong GetCntfrqEl0()
|
public static ulong GetCntfrqEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntfrqEl0;
|
return GetContext().CntfrqEl0;
|
||||||
|
@ -117,13 +133,25 @@ namespace ARMeilleure.Instructions
|
||||||
GetContext().Fpsr = (FPSR)value;
|
GetContext().Fpsr = (FPSR)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetFpscr(uint value)
|
||||||
|
{
|
||||||
|
ExecutionContext context = GetContext();
|
||||||
|
context.Fpsr = FPSR.A32Mask & (FPSR)value;
|
||||||
|
context.Fpcr = FPCR.A32Mask & (FPCR)value;
|
||||||
|
}
|
||||||
|
|
||||||
public static void SetTpidrEl0(ulong value)
|
public static void SetTpidrEl0(ulong value)
|
||||||
{
|
{
|
||||||
GetContext().TpidrEl0 = (long)value;
|
GetContext().TpidrEl0 = (long)value;
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region "Read"
|
public static void SetTpidrEl032(uint value)
|
||||||
|
{
|
||||||
|
GetContext().TpidrEl0 = (long)value;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "Read"
|
||||||
public static byte ReadByte(ulong address)
|
public static byte ReadByte(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadByte((long)address);
|
return GetMemoryManager().ReadByte((long)address);
|
||||||
|
|
|
@ -3,12 +3,14 @@ using System;
|
||||||
namespace ARMeilleure.State
|
namespace ARMeilleure.State
|
||||||
{
|
{
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum FPCR
|
public enum FPCR : ulong
|
||||||
{
|
{
|
||||||
Ufe = 1 << 11,
|
Ufe = 1 << 11,
|
||||||
Fz = 1 << 24,
|
Fz = 1 << 24,
|
||||||
Dn = 1 << 25,
|
Dn = 1 << 25,
|
||||||
Ahp = 1 << 26
|
Ahp = 1 << 26,
|
||||||
|
|
||||||
|
A32Mask = 0x07ffff00
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FPCRExtensions
|
public static class FPCRExtensions
|
||||||
|
|
|
@ -3,9 +3,11 @@ using System;
|
||||||
namespace ARMeilleure.State
|
namespace ARMeilleure.State
|
||||||
{
|
{
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum FPSR
|
public enum FPSR : ulong
|
||||||
{
|
{
|
||||||
Ufc = 1 << 3,
|
Ufc = 1 << 3,
|
||||||
Qc = 1 << 27
|
Qc = 1 << 27,
|
||||||
|
|
||||||
|
A32Mask = 0xf800000f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,25 +72,46 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ARM32.
|
|
||||||
long framePointer = (long)context.GetX(29);
|
|
||||||
|
|
||||||
trace.AppendLine($"Process: {_owner.Name}, PID: {_owner.Pid}");
|
trace.AppendLine($"Process: {_owner.Name}, PID: {_owner.Pid}");
|
||||||
|
|
||||||
while (framePointer != 0)
|
if (context.IsAarch32)
|
||||||
{
|
{
|
||||||
if ((framePointer & 7) != 0 ||
|
long framePointer = (long)context.GetX(0xd);
|
||||||
!_owner.CpuMemory.IsMapped(framePointer) ||
|
while (framePointer != 0)
|
||||||
!_owner.CpuMemory.IsMapped(framePointer + 8))
|
|
||||||
{
|
{
|
||||||
break;
|
if ((framePointer & 7) != 0 ||
|
||||||
|
!_owner.CpuMemory.IsMapped(framePointer) ||
|
||||||
|
!_owner.CpuMemory.IsMapped(framePointer + 4))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: This is the return address, we need to subtract one instruction
|
||||||
|
// worth of bytes to get the branch instruction address.
|
||||||
|
AppendTrace(_owner.CpuMemory.ReadInt32(framePointer + 4) - 4);
|
||||||
|
|
||||||
|
framePointer = _owner.CpuMemory.ReadInt32(framePointer);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long framePointer = (long)context.GetX(29);
|
||||||
|
|
||||||
// Note: This is the return address, we need to subtract one instruction
|
while (framePointer != 0)
|
||||||
// worth of bytes to get the branch instruction address.
|
{
|
||||||
AppendTrace(_owner.CpuMemory.ReadInt64(framePointer + 8) - 4);
|
if ((framePointer & 7) != 0 ||
|
||||||
|
!_owner.CpuMemory.IsMapped(framePointer) ||
|
||||||
|
!_owner.CpuMemory.IsMapped(framePointer + 8))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
framePointer = _owner.CpuMemory.ReadInt64(framePointer);
|
// Note: This is the return address, we need to subtract one instruction
|
||||||
|
// worth of bytes to get the branch instruction address.
|
||||||
|
AppendTrace(_owner.CpuMemory.ReadInt64(framePointer + 8) - 4);
|
||||||
|
|
||||||
|
framePointer = _owner.CpuMemory.ReadInt64(framePointer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return trace.ToString();
|
return trace.ToString();
|
||||||
|
|
|
@ -257,6 +257,15 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
return GetInfo(id, handle, subId, out value);
|
return GetInfo(id, handle, subId, out value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KernelResult GetInfo32(uint subIdLo, uint id, int handle, uint subIdHi, out uint valueLo, out uint valueHi)
|
||||||
|
{
|
||||||
|
long value;
|
||||||
|
KernelResult result = GetInfo(id, handle, subIdHi | ((long)subIdLo << 32), out value);
|
||||||
|
valueLo = (uint)(value >> 32);
|
||||||
|
valueHi = (uint)value;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private KernelResult GetInfo(uint id, int handle, long subId, out long value)
|
private KernelResult GetInfo(uint id, int handle, long subId, out long value)
|
||||||
{
|
{
|
||||||
value = 0;
|
value = 0;
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
|
@ -84,7 +85,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
_svcFuncs32 = new Dictionary<int, string>
|
_svcFuncs32 = new Dictionary<int, string>
|
||||||
{
|
{
|
||||||
{ 0x06, nameof(SvcHandler.QueryMemory32) },
|
{ 0x06, nameof(SvcHandler.QueryMemory32) },
|
||||||
{ 0x27, nameof(SvcHandler.OutputDebugString32) }
|
{ 0x27, nameof(SvcHandler.OutputDebugString32) },
|
||||||
|
{ 0x29, nameof(SvcHandler.GetInfo64) }
|
||||||
};
|
};
|
||||||
|
|
||||||
_svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80];
|
_svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80];
|
||||||
|
@ -126,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||||
|
|
||||||
int maxArgs = aarch32 ? SvcFuncMaxArguments32 : SvcFuncMaxArguments;
|
int maxArgs = aarch32 ? SvcFuncMaxArguments32 : SvcFuncMaxArguments;
|
||||||
|
|
||||||
if (methodArgs.Length > maxArgs)
|
if (methodArgs.Count(x => !x.IsOut) > maxArgs)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is {maxArgs}.");
|
throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is {maxArgs}.");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue