commit
a3ce90a23d
347 changed files with 9659 additions and 4749 deletions
|
@ -26,6 +26,10 @@
|
|||
|
||||
Enable the Fatal Logging (Enabled in Debug recommanded).
|
||||
|
||||
- `Logging_Enable_Ipc` *(bool)*
|
||||
|
||||
Enable the Ipc Message Logging.
|
||||
|
||||
- `Logging_Enable_LogFile` *(bool)*
|
||||
|
||||
Enable writing the logging inside a Ryujinx.log file.
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace ChocolArm64
|
|||
#region "OpCode Table"
|
||||
//Integer
|
||||
Set("x0011010000xxxxx000000xxxxxxxxxx", AInstEmit.Adc, typeof(AOpCodeAluRs));
|
||||
Set("x0111010000xxxxx000000xxxxxxxxxx", AInstEmit.Adcs, typeof(AOpCodeAluRs));
|
||||
Set("x00100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluImm));
|
||||
Set("x0001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRs));
|
||||
Set("x0001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRx));
|
||||
|
@ -47,9 +48,11 @@ namespace ChocolArm64
|
|||
Set("x1011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csneg, typeof(AOpCodeCsel));
|
||||
Set("11010101000000110011xxxx10111111", AInstEmit.Dmb, typeof(AOpCodeSystem));
|
||||
Set("11010101000000110011xxxx10011111", AInstEmit.Dsb, typeof(AOpCodeSystem));
|
||||
Set("x1001010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eon, typeof(AOpCodeAluRs));
|
||||
Set("x10100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluImm));
|
||||
Set("x1001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluRs));
|
||||
Set("x00100111x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Extr, typeof(AOpCodeAluRs));
|
||||
Set("11010101000000110010xxxxxxx11111", AInstEmit.Hint, typeof(AOpCodeSystem));
|
||||
Set("xx001000110xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldar, typeof(AOpCodeMemEx));
|
||||
Set("1x001000011xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxp, typeof(AOpCodeMemEx));
|
||||
Set("xx001000010xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxr, typeof(AOpCodeMemEx));
|
||||
|
@ -88,6 +91,7 @@ namespace ChocolArm64
|
|||
Set("1101101011000000000011xxxxxxxxxx", AInstEmit.Rev64, typeof(AOpCodeAlu));
|
||||
Set("x0011010110xxxxx001011xxxxxxxxxx", AInstEmit.Rorv, typeof(AOpCodeAluRs));
|
||||
Set("x1011010000xxxxx000000xxxxxxxxxx", AInstEmit.Sbc, typeof(AOpCodeAluRs));
|
||||
Set("x1111010000xxxxx000000xxxxxxxxxx", AInstEmit.Sbcs, typeof(AOpCodeAluRs));
|
||||
Set("x00100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sbfm, typeof(AOpCodeBfm));
|
||||
Set("x0011010110xxxxx000011xxxxxxxxxx", AInstEmit.Sdiv, typeof(AOpCodeAluRs));
|
||||
Set("10011011001xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Smaddl, typeof(AOpCodeMul));
|
||||
|
@ -138,57 +142,70 @@ namespace ChocolArm64
|
|||
Set("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd));
|
||||
Set("0>001110<<100000101010xxxxxxxxxx", AInstEmit.Cmlt_V, typeof(AOpCodeSimd));
|
||||
Set("0>001110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmtst_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x00111000100000010110xxxxxxxxxx", AInstEmit.Cnt_V, typeof(AOpCodeSimd));
|
||||
Set("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns));
|
||||
Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns));
|
||||
Set("0x001110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_V, typeof(AOpCodeSimdIns));
|
||||
Set("0x101110001xxxxx000111xxxxxxxxxx", AInstEmit.Eor_V, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd));
|
||||
Set("00011110xx1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011100x1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx1xxxxxxxxx01xxxxx0xxxx", AInstEmit.Fccmp_S, typeof(AOpCodeSimdFcond));
|
||||
Set("00011110xx1xxxxx001000xxxxx0x000", AInstEmit.Fcmp_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond));
|
||||
Set("00011110xx10001xx10000xxxxxxxxxx", AInstEmit.Fcvt_S, typeof(AOpCodeSimd));
|
||||
Set("x0011110xx100100000000xxxxxxxxxx", AInstEmit.Fcvtas_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x0011110xx100101000000xxxxxxxxxx", AInstEmit.Fcvtau_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x0011110xx110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x0011110xx011000xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzs_Gp_Fix, typeof(AOpCodeSimdCvt));
|
||||
Set("0x0011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimd));
|
||||
Set("0>101110000xxxxx0<xxx0xxxxxxxxxx", AInstEmit.Ext_V, typeof(AOpCodeSimdExt));
|
||||
Set("011111101x1xxxxx110101xxxxxxxxxx", AInstEmit.Fabd_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd));
|
||||
Set("000111100x1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>0011100<1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxxxxxx01xxxxx0xxxx", AInstEmit.Fccmp_S, typeof(AOpCodeSimdFcond));
|
||||
Set("000111100x1xxxxxxxxx01xxxxx1xxxx", AInstEmit.Fccmpe_S, typeof(AOpCodeSimdFcond));
|
||||
Set("000111100x1xxxxx001000xxxxx0x000", AInstEmit.Fcmp_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond));
|
||||
Set("000111100x10001xx10000xxxxxxxxxx", AInstEmit.Fcvt_S, typeof(AOpCodeSimd));
|
||||
Set("x00111100x100100000000xxxxxxxxxx", AInstEmit.Fcvtas_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x00111100x100101000000xxxxxxxxxx", AInstEmit.Fcvtau_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("0x0011100x100001011110xxxxxxxxxx", AInstEmit.Fcvtl_V, typeof(AOpCodeSimd));
|
||||
Set("x00111100x110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x00111100x110001000000xxxxxxxxxx", AInstEmit.Fcvtmu_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("0x0011100x100001011010xxxxxxxxxx", AInstEmit.Fcvtn_V, typeof(AOpCodeSimd));
|
||||
Set("x00111100x101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x00111100x101001000000xxxxxxxxxx", AInstEmit.Fcvtpu_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x00111100x111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x00111100x011000xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzs_Gp_Fix, typeof(AOpCodeSimdCvt));
|
||||
Set("0>0011101<100001101110xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimd));
|
||||
Set("0x0011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimdShImm));
|
||||
Set("x0011110xx111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x0011110xx011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Gp_Fix, typeof(AOpCodeSimdCvt));
|
||||
Set("0x1011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimd));
|
||||
Set("x00111100x111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x00111100x011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Gp_Fix, typeof(AOpCodeSimdCvt));
|
||||
Set("0>1011101<100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimd));
|
||||
Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimdShImm));
|
||||
Set("00011110xx1xxxxx000110xxxxxxxxxx", AInstEmit.Fdiv_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011111xx0xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fmadd_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx1xxxxx010010xxxxxxxxxx", AInstEmit.Fmax_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx1xxxxx011010xxxxxxxxxx", AInstEmit.Fmaxnm_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011100x1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011111<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Ve, typeof(AOpCodeSimdRegElem));
|
||||
Set("00011110xx100000010000xxxxxxxxxx", AInstEmit.Fmov_S, typeof(AOpCodeSimd));
|
||||
Set("000111100x1xxxxx000110xxxxxxxxxx", AInstEmit.Fdiv_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>1011100<1xxxxx111111xxxxxxxxxx", AInstEmit.Fdiv_V, typeof(AOpCodeSimdReg));
|
||||
Set("000111110x0xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fmadd_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx010010xxxxxxxxxx", AInstEmit.Fmax_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx011010xxxxxxxxxx", AInstEmit.Fmaxnm_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>0011100<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011111<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
Set("000111100x100000010000xxxxxxxxxx", AInstEmit.Fmov_S, typeof(AOpCodeSimd));
|
||||
Set("00011110xx1xxxxxxxx100xxxxxxxxxx", AInstEmit.Fmov_Si, typeof(AOpCodeSimdFmov));
|
||||
Set("0xx0111100000xxx111101xxxxxxxxxx", AInstEmit.Fmov_V, typeof(AOpCodeSimdImm));
|
||||
Set("x0011110xx100110000000xxxxxxxxxx", AInstEmit.Fmov_Ftoi, typeof(AOpCodeSimdCvt));
|
||||
Set("x0011110xx100111000000xxxxxxxxxx", AInstEmit.Fmov_Itof, typeof(AOpCodeSimdCvt));
|
||||
Set("x0011110xx101110000000xxxxxxxxxx", AInstEmit.Fmov_Ftoi1, typeof(AOpCodeSimdCvt));
|
||||
Set("x0011110xx101111000000xxxxxxxxxx", AInstEmit.Fmov_Itof1, typeof(AOpCodeSimdCvt));
|
||||
Set("00011111xx0xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fmsub_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx1xxxxx000010xxxxxxxxxx", AInstEmit.Fmul_S, typeof(AOpCodeSimdReg));
|
||||
Set("0x1011100x1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Ve, typeof(AOpCodeSimdRegElem));
|
||||
Set("00011110xx100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx1xxxxx100010xxxxxxxxxx", AInstEmit.Fnmul_S, typeof(AOpCodeSimdReg));
|
||||
Set("00011110xx100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd));
|
||||
Set("00011110xx100101010000xxxxxxxxxx", AInstEmit.Frintm_S, typeof(AOpCodeSimd));
|
||||
Set("00011110xx100001110000xxxxxxxxxx", AInstEmit.Fsqrt_S, typeof(AOpCodeSimd));
|
||||
Set("00011110xx1xxxxx001110xxxxxxxxxx", AInstEmit.Fsub_S, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011101x1xxxxx110101xxxxxxxxxx", AInstEmit.Fsub_V, typeof(AOpCodeSimdReg));
|
||||
Set("x00111100x100110000000xxxxxxxxxx", AInstEmit.Fmov_Ftoi, typeof(AOpCodeSimdCvt));
|
||||
Set("x00111100x100111000000xxxxxxxxxx", AInstEmit.Fmov_Itof, typeof(AOpCodeSimdCvt));
|
||||
Set("1001111010101110000000xxxxxxxxxx", AInstEmit.Fmov_Ftoi1, typeof(AOpCodeSimdCvt));
|
||||
Set("1001111010101111000000xxxxxxxxxx", AInstEmit.Fmov_Itof1, typeof(AOpCodeSimdCvt));
|
||||
Set("000111110x0xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fmsub_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx000010xxxxxxxxxx", AInstEmit.Fmul_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>1011100<1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
Set("000111100x100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111110x1xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fnmsub_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx100010xxxxxxxxxx", AInstEmit.Fnmul_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd));
|
||||
Set("000111100x100101010000xxxxxxxxxx", AInstEmit.Frintm_S, typeof(AOpCodeSimd));
|
||||
Set("0>0011100<100001100110xxxxxxxxxx", AInstEmit.Frintm_V, typeof(AOpCodeSimd));
|
||||
Set("000111100x100100110000xxxxxxxxxx", AInstEmit.Frintp_S, typeof(AOpCodeSimd));
|
||||
Set("000111100x100111010000xxxxxxxxxx", AInstEmit.Frintx_S, typeof(AOpCodeSimd));
|
||||
Set("000111100x100001110000xxxxxxxxxx", AInstEmit.Fsqrt_S, typeof(AOpCodeSimd));
|
||||
Set("000111100x1xxxxx001110xxxxxxxxxx", AInstEmit.Fsub_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>0011101<1xxxxx110101xxxxxxxxxx", AInstEmit.Fsub_V, typeof(AOpCodeSimdReg));
|
||||
Set("01001110000xxxxx000111xxxxxxxxxx", AInstEmit.Ins_Gp, typeof(AOpCodeSimdIns));
|
||||
Set("01101110000xxxxx0xxxx1xxxxxxxxxx", AInstEmit.Ins_V, typeof(AOpCodeSimdIns));
|
||||
Set("0x00110001000000xxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms, typeof(AOpCodeSimdMemMs));
|
||||
|
@ -209,6 +226,7 @@ namespace ChocolArm64
|
|||
Set("0x00111100000xxx110x01xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));
|
||||
Set("0xx0111100000xxx111001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));
|
||||
Set("0x001110<<1xxxxx100111xxxxxxxxxx", AInstEmit.Mul_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001111xxxxxxxx1000x0xxxxxxxxxx", AInstEmit.Mul_Ve, typeof(AOpCodeSimdRegElem));
|
||||
Set("0x10111100000xxx0xx001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm));
|
||||
Set("0x10111100000xxx10x001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm));
|
||||
Set("0x10111100000xxx110x01xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm));
|
||||
|
@ -216,19 +234,24 @@ namespace ChocolArm64
|
|||
Set("0x10111000100000010110xxxxxxxxxx", AInstEmit.Not_V, typeof(AOpCodeSimd));
|
||||
Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x00111100000xxx<<x101xxxxxxxxxx", AInstEmit.Orr_Vi, typeof(AOpCodeSimdImm));
|
||||
Set("0x001110<<100000000010xxxxxxxxxx", AInstEmit.Rev64_V, typeof(AOpCodeSimd));
|
||||
Set("0x001110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Saddw_V, typeof(AOpCodeSimdReg));
|
||||
Set("x0011110xx100010000000xxxxxxxxxx", AInstEmit.Scvtf_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("010111100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_S, typeof(AOpCodeSimd));
|
||||
Set("0x0011100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_V, typeof(AOpCodeSimd));
|
||||
Set("010111110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_S, typeof(AOpCodeSimdShImm));
|
||||
Set("0x0011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x101110<<100001001110xxxxxxxxxx", AInstEmit.Shll_V, typeof(AOpCodeSimd));
|
||||
Set("0x00111100>>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110<<1xxxxx100000xxxxxxxxxx", AInstEmit.Smlal_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V, typeof(AOpCodeSimdShImm));
|
||||
Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S, typeof(AOpCodeSimdShImm));
|
||||
Set("0x0011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x0011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Ssra_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
||||
Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
||||
Set("0x00110100000000xx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs));
|
||||
|
@ -249,13 +272,17 @@ namespace ChocolArm64
|
|||
Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd));
|
||||
Set("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd));
|
||||
Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
||||
Set("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm));
|
||||
Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm));
|
||||
Set("0x1011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110xx0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110<<100001001010xxxxxxxxxx", AInstEmit.Xtn_V, typeof(AOpCodeSimd));
|
||||
Set("0x001110xx0xxxxx001110xxxxxxxxxx", AInstEmit.Zip1_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110xx0xxxxx011110xxxxxxxxxx", AInstEmit.Zip2_V, typeof(AOpCodeSimdReg));
|
||||
#endregion
|
||||
}
|
||||
|
4
ChocolArm64/AOptimizations.cs
Normal file
4
ChocolArm64/AOptimizations.cs
Normal file
|
@ -0,0 +1,4 @@
|
|||
public static class AOptimizations
|
||||
{
|
||||
public static bool DisableMemoryChecks = false;
|
||||
}
|
|
@ -10,63 +10,50 @@ namespace ChocolArm64
|
|||
public AThreadState ThreadState { get; private set; }
|
||||
public AMemory Memory { get; private set; }
|
||||
|
||||
public long EntryPoint { get; private set; }
|
||||
private long EntryPoint;
|
||||
|
||||
private ATranslator Translator;
|
||||
|
||||
private ThreadPriority Priority;
|
||||
|
||||
private Thread Work;
|
||||
|
||||
public event EventHandler WorkFinished;
|
||||
|
||||
public int ThreadId => ThreadState.ThreadId;
|
||||
|
||||
public bool IsAlive => Work.IsAlive;
|
||||
private int IsExecuting;
|
||||
|
||||
private bool IsExecuting;
|
||||
|
||||
private object ExecuteLock;
|
||||
|
||||
public AThread(AMemory Memory, ThreadPriority Priority, long EntryPoint)
|
||||
public AThread(ATranslator Translator, AMemory Memory, long EntryPoint)
|
||||
{
|
||||
this.Translator = Translator;
|
||||
this.Memory = Memory;
|
||||
this.Priority = Priority;
|
||||
this.EntryPoint = EntryPoint;
|
||||
|
||||
ThreadState = new AThreadState();
|
||||
Translator = new ATranslator(this);
|
||||
ExecuteLock = new object();
|
||||
}
|
||||
|
||||
public void StopExecution() => Translator.StopExecution();
|
||||
ThreadState.Running = true;
|
||||
}
|
||||
|
||||
public bool Execute()
|
||||
{
|
||||
lock (ExecuteLock)
|
||||
if (Interlocked.Exchange(ref IsExecuting, 1) == 1)
|
||||
{
|
||||
if (IsExecuting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IsExecuting = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Work = new Thread(delegate()
|
||||
{
|
||||
Translator.ExecuteSubroutine(EntryPoint);
|
||||
Translator.ExecuteSubroutine(this, EntryPoint);
|
||||
|
||||
Memory.RemoveMonitor(ThreadId);
|
||||
|
||||
WorkFinished?.Invoke(this, EventArgs.Empty);
|
||||
});
|
||||
|
||||
Work.Priority = Priority;
|
||||
|
||||
Work.Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void StopExecution() => ThreadState.Running = false;
|
||||
}
|
||||
}
|
134
ChocolArm64/ATranslatedSub.cs
Normal file
134
ChocolArm64/ATranslatedSub.cs
Normal file
|
@ -0,0 +1,134 @@
|
|||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace ChocolArm64
|
||||
{
|
||||
class ATranslatedSub
|
||||
{
|
||||
private delegate long AA64Subroutine(AThreadState Register, AMemory Memory);
|
||||
|
||||
private AA64Subroutine ExecDelegate;
|
||||
|
||||
public static int StateArgIdx { get; private set; }
|
||||
public static int MemoryArgIdx { get; private set; }
|
||||
|
||||
public static Type[] FixedArgTypes { get; private set; }
|
||||
|
||||
public DynamicMethod Method { get; private set; }
|
||||
|
||||
public ReadOnlyCollection<ARegister> Params { get; private set; }
|
||||
|
||||
private HashSet<long> Callees;
|
||||
|
||||
private ATranslatedSubType Type;
|
||||
|
||||
private int CallCount;
|
||||
|
||||
private bool NeedsReJit;
|
||||
|
||||
private int MinCallCountForReJit = 250;
|
||||
|
||||
public ATranslatedSub(DynamicMethod Method, List<ARegister> Params, HashSet<long> Callees)
|
||||
{
|
||||
if (Method == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Method));
|
||||
}
|
||||
|
||||
if (Params == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Params));
|
||||
}
|
||||
|
||||
if (Callees == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Callees));
|
||||
}
|
||||
|
||||
this.Method = Method;
|
||||
this.Params = Params.AsReadOnly();
|
||||
this.Callees = Callees;
|
||||
|
||||
PrepareDelegate();
|
||||
}
|
||||
|
||||
static ATranslatedSub()
|
||||
{
|
||||
MethodInfo MthdInfo = typeof(AA64Subroutine).GetMethod("Invoke");
|
||||
|
||||
ParameterInfo[] Params = MthdInfo.GetParameters();
|
||||
|
||||
FixedArgTypes = new Type[Params.Length];
|
||||
|
||||
for (int Index = 0; Index < Params.Length; Index++)
|
||||
{
|
||||
Type ParamType = Params[Index].ParameterType;
|
||||
|
||||
FixedArgTypes[Index] = ParamType;
|
||||
|
||||
if (ParamType == typeof(AThreadState))
|
||||
{
|
||||
StateArgIdx = Index;
|
||||
}
|
||||
else if (ParamType == typeof(AMemory))
|
||||
{
|
||||
MemoryArgIdx = Index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareDelegate()
|
||||
{
|
||||
string Name = $"{Method.Name}_Dispatch";
|
||||
|
||||
DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes);
|
||||
|
||||
ILGenerator Generator = Mthd.GetILGenerator();
|
||||
|
||||
Generator.EmitLdargSeq(FixedArgTypes.Length);
|
||||
|
||||
foreach (ARegister Reg in Params)
|
||||
{
|
||||
Generator.EmitLdarg(StateArgIdx);
|
||||
|
||||
Generator.Emit(OpCodes.Ldfld, Reg.GetField());
|
||||
}
|
||||
|
||||
Generator.Emit(OpCodes.Call, Method);
|
||||
Generator.Emit(OpCodes.Ret);
|
||||
|
||||
ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine));
|
||||
}
|
||||
|
||||
public bool ShouldReJit()
|
||||
{
|
||||
if (Type == ATranslatedSubType.SubTier0)
|
||||
{
|
||||
if (CallCount < MinCallCountForReJit)
|
||||
{
|
||||
CallCount++;
|
||||
}
|
||||
|
||||
return CallCount == MinCallCountForReJit;
|
||||
}
|
||||
|
||||
return Type == ATranslatedSubType.SubTier1 && NeedsReJit;
|
||||
}
|
||||
|
||||
public long Execute(AThreadState ThreadState, AMemory Memory)
|
||||
{
|
||||
return ExecDelegate(ThreadState, Memory);
|
||||
}
|
||||
|
||||
public void SetType(ATranslatedSubType Type) => this.Type = Type;
|
||||
|
||||
public bool HasCallee(long Position) => Callees.Contains(Position);
|
||||
|
||||
public void MarkForReJit() => NeedsReJit = true;
|
||||
}
|
||||
}
|
9
ChocolArm64/ATranslatedSubType.cs
Normal file
9
ChocolArm64/ATranslatedSubType.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace ChocolArm64
|
||||
{
|
||||
enum ATranslatedSubType
|
||||
{
|
||||
SubBlock,
|
||||
SubTier0,
|
||||
SubTier1
|
||||
}
|
||||
}
|
192
ChocolArm64/ATranslator.cs
Normal file
192
ChocolArm64/ATranslator.cs
Normal file
|
@ -0,0 +1,192 @@
|
|||
using ChocolArm64.Decoder;
|
||||
using ChocolArm64.Events;
|
||||
using ChocolArm64.Instruction;
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.Translation;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace ChocolArm64
|
||||
{
|
||||
public class ATranslator
|
||||
{
|
||||
private HashSet<long> SubBlocks;
|
||||
|
||||
private ConcurrentDictionary<long, ATranslatedSub> CachedSubs;
|
||||
|
||||
private ConcurrentDictionary<long, string> SymbolTable;
|
||||
|
||||
public event EventHandler<ACpuTraceEventArgs> CpuTrace;
|
||||
|
||||
public bool EnableCpuTrace { get; set; }
|
||||
|
||||
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
||||
{
|
||||
SubBlocks = new HashSet<long>();
|
||||
|
||||
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
|
||||
|
||||
if (SymbolTable != null)
|
||||
{
|
||||
this.SymbolTable = new ConcurrentDictionary<long, string>(SymbolTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SymbolTable = new ConcurrentDictionary<long, string>();
|
||||
}
|
||||
}
|
||||
|
||||
internal void ExecuteSubroutine(AThread Thread, long Position)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (EnableCpuTrace)
|
||||
{
|
||||
if (!SymbolTable.TryGetValue(Position, out string SubName))
|
||||
{
|
||||
SubName = string.Empty;
|
||||
}
|
||||
|
||||
CpuTrace?.Invoke(this, new ACpuTraceEventArgs(Position, SubName));
|
||||
}
|
||||
|
||||
if (!CachedSubs.TryGetValue(Position, out ATranslatedSub Sub))
|
||||
{
|
||||
Sub = TranslateTier0(Thread.Memory, Position);
|
||||
}
|
||||
|
||||
if (Sub.ShouldReJit())
|
||||
{
|
||||
TranslateTier1(Thread.Memory, Position);
|
||||
}
|
||||
|
||||
Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
|
||||
}
|
||||
while (Position != 0 && Thread.ThreadState.Running);
|
||||
}
|
||||
|
||||
internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
|
||||
{
|
||||
if (OpCode.Emitter != AInstEmit.Bl)
|
||||
{
|
||||
Sub = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub);
|
||||
}
|
||||
|
||||
internal bool TryGetCachedSub(long Position, out ATranslatedSub Sub)
|
||||
{
|
||||
return CachedSubs.TryGetValue(Position, out Sub);
|
||||
}
|
||||
|
||||
internal bool HasCachedSub(long Position)
|
||||
{
|
||||
return CachedSubs.ContainsKey(Position);
|
||||
}
|
||||
|
||||
private ATranslatedSub TranslateTier0(AMemory Memory, long Position)
|
||||
{
|
||||
ABlock Block = ADecoder.DecodeBasicBlock(this, Memory, Position);
|
||||
|
||||
ABlock[] Graph = new ABlock[] { Block };
|
||||
|
||||
string SubName = GetSubName(Position);
|
||||
|
||||
AILEmitterCtx Context = new AILEmitterCtx(this, Graph, Block, SubName);
|
||||
|
||||
do
|
||||
{
|
||||
Context.EmitOpCode();
|
||||
}
|
||||
while (Context.AdvanceOpCode());
|
||||
|
||||
ATranslatedSub Subroutine = Context.GetSubroutine();
|
||||
|
||||
if (SubBlocks.Contains(Position))
|
||||
{
|
||||
SubBlocks.Remove(Position);
|
||||
|
||||
Subroutine.SetType(ATranslatedSubType.SubBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
Subroutine.SetType(ATranslatedSubType.SubTier0);
|
||||
}
|
||||
|
||||
CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
|
||||
|
||||
AOpCode LastOp = Block.GetLastOp();
|
||||
|
||||
if (LastOp.Emitter != AInstEmit.Ret &&
|
||||
LastOp.Emitter != AInstEmit.Br)
|
||||
{
|
||||
SubBlocks.Add(LastOp.Position + 4);
|
||||
}
|
||||
|
||||
return Subroutine;
|
||||
}
|
||||
|
||||
private void TranslateTier1(AMemory Memory, long Position)
|
||||
{
|
||||
(ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Memory, Position);
|
||||
|
||||
string SubName = GetSubName(Position);
|
||||
|
||||
PropagateName(Cfg.Graph, SubName);
|
||||
|
||||
AILEmitterCtx Context = new AILEmitterCtx(this, Cfg.Graph, Cfg.Root, SubName);
|
||||
|
||||
if (Context.CurrBlock.Position != Position)
|
||||
{
|
||||
Context.Emit(OpCodes.Br, Context.GetLabel(Position));
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
Context.EmitOpCode();
|
||||
}
|
||||
while (Context.AdvanceOpCode());
|
||||
|
||||
//Mark all methods that calls this method for ReJiting,
|
||||
//since we can now call it directly which is faster.
|
||||
foreach (ATranslatedSub TS in CachedSubs.Values)
|
||||
{
|
||||
if (TS.HasCallee(Position))
|
||||
{
|
||||
TS.MarkForReJit();
|
||||
}
|
||||
}
|
||||
|
||||
ATranslatedSub Subroutine = Context.GetSubroutine();
|
||||
|
||||
Subroutine.SetType(ATranslatedSubType.SubTier1);
|
||||
|
||||
CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
|
||||
}
|
||||
|
||||
private string GetSubName(long Position)
|
||||
{
|
||||
return SymbolTable.GetOrAdd(Position, $"Sub{Position:x16}");
|
||||
}
|
||||
|
||||
private void PropagateName(ABlock[] Graph, string Name)
|
||||
{
|
||||
foreach (ABlock Block in Graph)
|
||||
{
|
||||
AOpCode LastOp = Block.GetLastOp();
|
||||
|
||||
if (LastOp != null &&
|
||||
(LastOp.Emitter == AInstEmit.Bl ||
|
||||
LastOp.Emitter == AInstEmit.Blr))
|
||||
{
|
||||
SymbolTable.TryAdd(LastOp.Position + 4, Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
ChocolArm64/ChocolArm64.csproj
Normal file
15
ChocolArm64/ChocolArm64.csproj
Normal file
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -1,6 +1,7 @@
|
|||
using ChocolArm64.Instruction;
|
||||
using ChocolArm64.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
|
@ -8,7 +9,31 @@ namespace ChocolArm64.Decoder
|
|||
{
|
||||
static class ADecoder
|
||||
{
|
||||
public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(ATranslator Translator, long Start)
|
||||
private delegate object OpActivator(AInst Inst, long Position, int OpCode);
|
||||
|
||||
private static ConcurrentDictionary<Type, OpActivator> OpActivators;
|
||||
|
||||
static ADecoder()
|
||||
{
|
||||
OpActivators = new ConcurrentDictionary<Type, OpActivator>();
|
||||
}
|
||||
|
||||
public static ABlock DecodeBasicBlock(
|
||||
ATranslator Translator,
|
||||
AMemory Memory,
|
||||
long Start)
|
||||
{
|
||||
ABlock Block = new ABlock(Start);
|
||||
|
||||
FillBlock(Memory, Block);
|
||||
|
||||
return Block;
|
||||
}
|
||||
|
||||
public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(
|
||||
ATranslator Translator,
|
||||
AMemory Memory,
|
||||
long Start)
|
||||
{
|
||||
Dictionary<long, ABlock> Visited = new Dictionary<long, ABlock>();
|
||||
Dictionary<long, ABlock> VisitedEnd = new Dictionary<long, ABlock>();
|
||||
|
@ -35,7 +60,7 @@ namespace ChocolArm64.Decoder
|
|||
{
|
||||
ABlock Current = Blocks.Dequeue();
|
||||
|
||||
FillBlock(Translator.Thread.Memory, Current);
|
||||
FillBlock(Memory, Current);
|
||||
|
||||
//Set child blocks. "Branch" is the block the branch instruction
|
||||
//points to (when taken), "Next" is the block at the next address,
|
||||
|
@ -59,8 +84,8 @@ namespace ChocolArm64.Decoder
|
|||
}
|
||||
}
|
||||
|
||||
if ((!(LastOp is AOpCodeBImmAl) &&
|
||||
!(LastOp is AOpCodeBReg)) || HasCachedSub)
|
||||
if (!((LastOp is AOpCodeBImmAl) ||
|
||||
(LastOp is AOpCodeBReg)) || HasCachedSub)
|
||||
{
|
||||
Current.Next = Enqueue(Current.EndPosition);
|
||||
}
|
||||
|
@ -165,43 +190,39 @@ namespace ChocolArm64.Decoder
|
|||
|
||||
if (Inst.Type != null)
|
||||
{
|
||||
DecodedOpCode = CreateOpCode(Inst.Type, Inst, Position, OpCode);
|
||||
DecodedOpCode = MakeOpCode(Inst.Type, Inst, Position, OpCode);
|
||||
}
|
||||
|
||||
return DecodedOpCode;
|
||||
}
|
||||
|
||||
private delegate object OpActivator(AInst Inst, long Position, int OpCode);
|
||||
|
||||
private static Dictionary<Type, OpActivator> Activators = new Dictionary<Type, OpActivator>();
|
||||
|
||||
private static AOpCode CreateOpCode(Type Type, AInst Inst, long Position, int OpCode)
|
||||
private static AOpCode MakeOpCode(Type Type, AInst Inst, long Position, int OpCode)
|
||||
{
|
||||
if (Type == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Type));
|
||||
}
|
||||
|
||||
if (!Activators.TryGetValue(Type, out OpActivator CreateInstance))
|
||||
{
|
||||
Type[] ArgTypes = new Type[] { typeof(AInst), typeof(long), typeof(int) };
|
||||
|
||||
DynamicMethod Mthd = new DynamicMethod($"{Type.Name}_Create", Type, ArgTypes);
|
||||
|
||||
ILGenerator Generator = Mthd.GetILGenerator();
|
||||
|
||||
Generator.Emit(OpCodes.Ldarg_0);
|
||||
Generator.Emit(OpCodes.Ldarg_1);
|
||||
Generator.Emit(OpCodes.Ldarg_2);
|
||||
Generator.Emit(OpCodes.Newobj, Type.GetConstructor(ArgTypes));
|
||||
Generator.Emit(OpCodes.Ret);
|
||||
|
||||
CreateInstance = (OpActivator)Mthd.CreateDelegate(typeof(OpActivator));
|
||||
|
||||
Activators.Add(Type, CreateInstance);
|
||||
}
|
||||
OpActivator CreateInstance = OpActivators.GetOrAdd(Type, CacheOpActivator);
|
||||
|
||||
return (AOpCode)CreateInstance(Inst, Position, OpCode);
|
||||
}
|
||||
|
||||
private static OpActivator CacheOpActivator(Type Type)
|
||||
{
|
||||
Type[] ArgTypes = new Type[] { typeof(AInst), typeof(long), typeof(int) };
|
||||
|
||||
DynamicMethod Mthd = new DynamicMethod($"Make{Type.Name}", Type, ArgTypes);
|
||||
|
||||
ILGenerator Generator = Mthd.GetILGenerator();
|
||||
|
||||
Generator.Emit(OpCodes.Ldarg_0);
|
||||
Generator.Emit(OpCodes.Ldarg_1);
|
||||
Generator.Emit(OpCodes.Ldarg_2);
|
||||
Generator.Emit(OpCodes.Newobj, Type.GetConstructor(ArgTypes));
|
||||
Generator.Emit(OpCodes.Ret);
|
||||
|
||||
return (OpActivator)Mthd.CreateDelegate(typeof(OpActivator));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,8 +10,6 @@ namespace ChocolArm64.Decoder
|
|||
public int Opc { get; private set; }
|
||||
public int Size { get; protected set; }
|
||||
|
||||
public int SizeF => Size & 1;
|
||||
|
||||
public AOpCodeSimd(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
{
|
||||
Rd = (OpCode >> 0) & 0x1f;
|
14
ChocolArm64/Decoder/AOpCodeSimdExt.cs
Normal file
14
ChocolArm64/Decoder/AOpCodeSimdExt.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using ChocolArm64.Instruction;
|
||||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdExt : AOpCodeSimdReg
|
||||
{
|
||||
public int Imm4 { get; private set; }
|
||||
|
||||
public AOpCodeSimdExt(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
{
|
||||
Imm4 = (OpCode >> 11) & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,9 +4,9 @@ namespace ChocolArm64.Decoder
|
|||
{
|
||||
class AOpCodeSimdReg : AOpCodeSimd
|
||||
{
|
||||
public bool Bit3 { get; private set; }
|
||||
public int Ra { get; private set; }
|
||||
public int Rm { get; private set; }
|
||||
public bool Bit3 { get; private set; }
|
||||
public int Ra { get; private set; }
|
||||
public int Rm { get; protected set; }
|
||||
|
||||
public AOpCodeSimdReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
{
|
32
ChocolArm64/Decoder/AOpCodeSimdRegElem.cs
Normal file
32
ChocolArm64/Decoder/AOpCodeSimdRegElem.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using ChocolArm64.Instruction;
|
||||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdRegElem : AOpCodeSimdReg
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
|
||||
public AOpCodeSimdRegElem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case 1:
|
||||
Index = (OpCode >> 21) & 1 |
|
||||
(OpCode >> 10) & 2 |
|
||||
(OpCode >> 18) & 4;
|
||||
|
||||
Rm &= 0xf;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
Index = (OpCode >> 21) & 1 |
|
||||
(OpCode >> 10) & 2;
|
||||
|
||||
break;
|
||||
|
||||
default: Emitter = AInstEmit.Und; return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdRegElem : AOpCodeSimdReg
|
||||
class AOpCodeSimdRegElemF : AOpCodeSimdReg
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
|
||||
public AOpCodeSimdRegElem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdRegElemF(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
{
|
||||
if ((Size & 1) != 0)
|
||||
{
|
17
ChocolArm64/Events/ACpuTraceEventArgs.cs
Normal file
17
ChocolArm64/Events/ACpuTraceEventArgs.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace ChocolArm64.Events
|
||||
{
|
||||
public class ACpuTraceEventArgs : EventArgs
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
|
||||
public string SubName { get; private set; }
|
||||
|
||||
public ACpuTraceEventArgs(long Position, string SubName)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.SubName = SubName;
|
||||
}
|
||||
}
|
||||
}
|
14
ChocolArm64/Events/AInstExceptionEventArgs.cs
Normal file
14
ChocolArm64/Events/AInstExceptionEventArgs.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace ChocolArm64.Events
|
||||
{
|
||||
public class AInstExceptionEventArgs : EventArgs
|
||||
{
|
||||
public int Id { get; private set; }
|
||||
|
||||
public AInstExceptionEventArgs(int Id)
|
||||
{
|
||||
this.Id = Id;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace ChocolArm64.State
|
||||
namespace ChocolArm64.Events
|
||||
{
|
||||
public class AInstUndEventArgs : EventArgs
|
||||
public class AInstUndefinedEventArgs : EventArgs
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
public int RawOpCode { get; private set; }
|
||||
|
||||
public AInstUndEventArgs(long Position, int RawOpCode)
|
||||
public AInstUndefinedEventArgs(long Position, int RawOpCode)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.RawOpCode = RawOpCode;
|
|
@ -11,7 +11,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
static partial class AInstEmit
|
||||
{
|
||||
public static void Adc(AILEmitterCtx Context)
|
||||
public static void Adc(AILEmitterCtx Context) => EmitAdc(Context, false);
|
||||
public static void Adcs(AILEmitterCtx Context) => EmitAdc(Context, true);
|
||||
|
||||
private static void EmitAdc(AILEmitterCtx Context, bool SetFlags)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
|
||||
|
@ -27,11 +30,19 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (Context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_I8);
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
if (SetFlags)
|
||||
{
|
||||
Context.EmitZNFlagCheck();
|
||||
|
||||
EmitAdcsCCheck(Context);
|
||||
EmitAddsVCheck(Context);
|
||||
}
|
||||
|
||||
EmitDataStore(Context);
|
||||
}
|
||||
|
||||
|
@ -107,6 +118,16 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
||||
public static void Eon(AILEmitterCtx Context)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitDataStore(Context);
|
||||
}
|
||||
|
||||
public static void Eor(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Xor);
|
||||
|
||||
public static void Extr(AILEmitterCtx Context)
|
||||
|
@ -135,7 +156,10 @@ namespace ChocolArm64.Instruction
|
|||
public static void Lslv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shl);
|
||||
public static void Lsrv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shr_Un);
|
||||
|
||||
public static void Sbc(AILEmitterCtx Context)
|
||||
public static void Sbc(AILEmitterCtx Context) => EmitSbc(Context, false);
|
||||
public static void Sbcs(AILEmitterCtx Context) => EmitSbc(Context, true);
|
||||
|
||||
private static void EmitSbc(AILEmitterCtx Context, bool SetFlags)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
|
||||
|
@ -155,11 +179,19 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (Context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_I8);
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
if (SetFlags)
|
||||
{
|
||||
Context.EmitZNFlagCheck();
|
||||
|
||||
EmitSbcsCCheck(Context);
|
||||
EmitSubsVCheck(Context);
|
||||
}
|
||||
|
||||
EmitDataStore(Context);
|
||||
}
|
||||
|
|
@ -7,6 +7,31 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
static class AInstEmitAluHelper
|
||||
{
|
||||
public static void EmitAdcsCCheck(AILEmitterCtx Context)
|
||||
{
|
||||
//C = (Rd == Rn && CIn) || Rd < Rn
|
||||
Context.EmitSttmp();
|
||||
Context.EmitLdtmp();
|
||||
Context.EmitLdtmp();
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
|
||||
Context.Emit(OpCodes.Ceq);
|
||||
|
||||
Context.EmitLdflg((int)APState.CBit);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdtmp();
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
|
||||
Context.Emit(OpCodes.Clt_Un);
|
||||
Context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
}
|
||||
|
||||
public static void EmitAddsCCheck(AILEmitterCtx Context)
|
||||
{
|
||||
//C = Rd < Rn
|
||||
|
@ -41,6 +66,25 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitStflg((int)APState.VBit);
|
||||
}
|
||||
|
||||
public static void EmitSbcsCCheck(AILEmitterCtx Context)
|
||||
{
|
||||
//C = (Rn == Rm && CIn) || Rn > Rm
|
||||
EmitDataLoadOpers(Context);
|
||||
|
||||
Context.Emit(OpCodes.Ceq);
|
||||
|
||||
Context.EmitLdflg((int)APState.CBit);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
EmitDataLoadOpers(Context);
|
||||
|
||||
Context.Emit(OpCodes.Cgt_Un);
|
||||
Context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
}
|
||||
|
||||
public static void EmitSubsCCheck(AILEmitterCtx Context)
|
||||
{
|
||||
//C = Rn == Rm || Rn > Rm = !(Rn < Rm)
|
||||
|
@ -145,5 +189,24 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitStint(Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitSetNZCV(AILEmitterCtx Context, int NZCV)
|
||||
{
|
||||
Context.EmitLdc_I4((NZCV >> 0) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.VBit);
|
||||
|
||||
Context.EmitLdc_I4((NZCV >> 1) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
|
||||
Context.EmitLdc_I4((NZCV >> 2) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.ZBit);
|
||||
|
||||
Context.EmitLdc_I4((NZCV >> 3) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.NBit);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (Op.Pos + 1 == BitsCount)
|
||||
{
|
||||
EmitBfmShift(Context, OpCodes.Shr);
|
||||
EmitSbfmShift(Context);
|
||||
}
|
||||
else if (Op.Pos < Op.Shift)
|
||||
{
|
||||
|
@ -54,15 +54,6 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
EmitSbfmCast(Context, OpCodes.Conv_I4);
|
||||
}
|
||||
else if (Op.Shift == 0)
|
||||
{
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
Context.EmitLsl(BitsCount - 1 - Op.Pos);
|
||||
Context.EmitAsr(BitsCount - 1);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBfmLoadRn(Context);
|
||||
|
@ -87,7 +78,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (Op.Pos + 1 == Op.GetBitsCount())
|
||||
{
|
||||
EmitBfmShift(Context, OpCodes.Shr_Un);
|
||||
EmitUbfmShift(Context);
|
||||
}
|
||||
else if (Op.Pos < Op.Shift)
|
||||
{
|
||||
|
@ -166,19 +157,28 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitBfmShift(AILEmitterCtx Context, OpCode ILOp)
|
||||
private static void EmitSbfmShift(AILEmitterCtx Context)
|
||||
{
|
||||
EmitBfmShift(Context, true);
|
||||
}
|
||||
|
||||
private static void EmitUbfmShift(AILEmitterCtx Context)
|
||||
{
|
||||
EmitBfmShift(Context, false);
|
||||
}
|
||||
|
||||
private static void EmitBfmShift(AILEmitterCtx Context, bool Signed)
|
||||
{
|
||||
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||
|
||||
if (Op.Shift > 0)
|
||||
{
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
Context.EmitLdc_I4(Op.Shift);
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
Context.EmitLdc_I4(Op.Shift);
|
||||
|
||||
Context.Emit(ILOp);
|
||||
Context.Emit(Signed
|
||||
? OpCodes.Shr
|
||||
: OpCodes.Shr_Un);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitBfmLsl(AILEmitterCtx Context)
|
|
@ -44,16 +44,15 @@ namespace ChocolArm64.Instruction
|
|||
Context.Emit(OpCodes.Neg);
|
||||
}
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ using ChocolArm64.Decoder;
|
|||
using ChocolArm64.State;
|
||||
using ChocolArm64.Translation;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
|
@ -33,10 +34,32 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
Context.EmitCall(MthdInfo);
|
||||
|
||||
//Check if the thread should still be running, if it isn't then we return 0
|
||||
//to force a return to the dispatcher and then exit the thread.
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Running));
|
||||
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.Brtrue_S, LblEnd);
|
||||
|
||||
Context.EmitLdc_I8(0);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
|
||||
if (Context.CurrBlock.Next != null)
|
||||
{
|
||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitLdc_I8(Op.Position + 4);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Und(AILEmitterCtx Context)
|
||||
|
@ -60,6 +83,12 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitLdc_I8(Op.Position + 4);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,14 +11,24 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;
|
||||
|
||||
Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm));
|
||||
if (Context.CurrBlock.Branch != null)
|
||||
{
|
||||
Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm));
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitStoreState();
|
||||
Context.EmitLdc_I8(Op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
|
||||
public static void B_Cond(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeBImmCond Op = (AOpCodeBImmCond)Context.CurrOp;
|
||||
|
||||
Context.EmitCondBranch(Context.GetLabel(Op.Imm), Op.Cond);
|
||||
EmitBranch(Context, Op.Cond);
|
||||
}
|
||||
|
||||
public static void Bl(AILEmitterCtx Context)
|
||||
|
@ -48,10 +58,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
if (Context.CurrBlock.Next != null)
|
||||
{
|
||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||
}
|
||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -93,7 +100,7 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitLdintzr(Op.Rt);
|
||||
Context.EmitLdc_I(0);
|
||||
|
||||
Context.Emit(ILOp, Context.GetLabel(Op.Imm));
|
||||
EmitBranch(Context, ILOp);
|
||||
}
|
||||
|
||||
public static void Ret(AILEmitterCtx Context)
|
||||
|
@ -118,7 +125,65 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
Context.EmitLdc_I(0);
|
||||
|
||||
Context.Emit(ILOp, Context.GetLabel(Op.Imm));
|
||||
EmitBranch(Context, ILOp);
|
||||
}
|
||||
|
||||
private static void EmitBranch(AILEmitterCtx Context, ACond Cond)
|
||||
{
|
||||
AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp;
|
||||
|
||||
if (Context.CurrBlock.Next != null &&
|
||||
Context.CurrBlock.Branch != null)
|
||||
{
|
||||
Context.EmitCondBranch(Context.GetLabel(Op.Imm), Cond);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitStoreState();
|
||||
|
||||
AILLabel LblTaken = new AILLabel();
|
||||
|
||||
Context.EmitCondBranch(LblTaken, Cond);
|
||||
|
||||
Context.EmitLdc_I8(Op.Position + 4);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
|
||||
Context.MarkLabel(LblTaken);
|
||||
|
||||
Context.EmitLdc_I8(Op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitBranch(AILEmitterCtx Context, OpCode ILOp)
|
||||
{
|
||||
AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp;
|
||||
|
||||
if (Context.CurrBlock.Next != null &&
|
||||
Context.CurrBlock.Branch != null)
|
||||
{
|
||||
Context.Emit(ILOp, Context.GetLabel(Op.Imm));
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitStoreState();
|
||||
|
||||
AILLabel LblTaken = new AILLabel();
|
||||
|
||||
Context.Emit(ILOp, LblTaken);
|
||||
|
||||
Context.EmitLdc_I8(Op.Position + 4);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
|
||||
Context.MarkLabel(LblTaken);
|
||||
|
||||
Context.EmitLdc_I8(Op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
188
ChocolArm64/Instruction/AInstEmitMemoryHelper.cs
Normal file
188
ChocolArm64/Instruction/AInstEmitMemoryHelper.cs
Normal file
|
@ -0,0 +1,188 @@
|
|||
using ChocolArm64.Decoder;
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.Translation;
|
||||
using System;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static class AInstEmitMemoryHelper
|
||||
{
|
||||
private enum Extension
|
||||
{
|
||||
Zx,
|
||||
Sx32,
|
||||
Sx64
|
||||
}
|
||||
|
||||
public static void EmitReadZxCall(AILEmitterCtx Context, int Size)
|
||||
{
|
||||
EmitReadCall(Context, Extension.Zx, Size);
|
||||
}
|
||||
|
||||
public static void EmitReadSx32Call(AILEmitterCtx Context, int Size)
|
||||
{
|
||||
EmitReadCall(Context, Extension.Sx32, Size);
|
||||
}
|
||||
|
||||
public static void EmitReadSx64Call(AILEmitterCtx Context, int Size)
|
||||
{
|
||||
EmitReadCall(Context, Extension.Sx64, Size);
|
||||
}
|
||||
|
||||
private static void EmitReadCall(AILEmitterCtx Context, Extension Ext, int Size)
|
||||
{
|
||||
bool IsSimd = GetIsSimd(Context);
|
||||
|
||||
string Name = null;
|
||||
|
||||
if (Size < 0 || Size > (IsSimd ? 4 : 3))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
if (IsSimd)
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case 0: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.ReadVector8Unchecked)
|
||||
: nameof(AMemory.ReadVector8); break;
|
||||
|
||||
case 1: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.ReadVector16Unchecked)
|
||||
: nameof(AMemory.ReadVector16); break;
|
||||
|
||||
case 2: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.ReadVector32Unchecked)
|
||||
: nameof(AMemory.ReadVector32); break;
|
||||
|
||||
case 3: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.ReadVector64Unchecked)
|
||||
: nameof(AMemory.ReadVector64); break;
|
||||
|
||||
case 4: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.ReadVector128Unchecked)
|
||||
: nameof(AMemory.ReadVector128); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case 0: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.ReadByteUnchecked)
|
||||
: nameof(AMemory.ReadByte); break;
|
||||
|
||||
case 1: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.ReadUInt16Unchecked)
|
||||
: nameof(AMemory.ReadUInt16); break;
|
||||
|
||||
case 2: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.ReadUInt32Unchecked)
|
||||
: nameof(AMemory.ReadUInt32); break;
|
||||
|
||||
case 3: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.ReadUInt64Unchecked)
|
||||
: nameof(AMemory.ReadUInt64); break;
|
||||
}
|
||||
}
|
||||
|
||||
Context.EmitCall(typeof(AMemory), Name);
|
||||
|
||||
if (!IsSimd)
|
||||
{
|
||||
if (Ext == Extension.Sx32 ||
|
||||
Ext == Extension.Sx64)
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case 0: Context.Emit(OpCodes.Conv_I1); break;
|
||||
case 1: Context.Emit(OpCodes.Conv_I2); break;
|
||||
case 2: Context.Emit(OpCodes.Conv_I4); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Size < 3)
|
||||
{
|
||||
Context.Emit(Ext == Extension.Sx64
|
||||
? OpCodes.Conv_I8
|
||||
: OpCodes.Conv_U8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitWriteCall(AILEmitterCtx Context, int Size)
|
||||
{
|
||||
bool IsSimd = GetIsSimd(Context);
|
||||
|
||||
string Name = null;
|
||||
|
||||
if (Size < 0 || Size > (IsSimd ? 4 : 3))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
if (Size < 3 && !IsSimd)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_I4);
|
||||
}
|
||||
|
||||
if (IsSimd)
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case 0: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.WriteVector8Unchecked)
|
||||
: nameof(AMemory.WriteVector8); break;
|
||||
|
||||
case 1: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.WriteVector16Unchecked)
|
||||
: nameof(AMemory.WriteVector16); break;
|
||||
|
||||
case 2: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.WriteVector32Unchecked)
|
||||
: nameof(AMemory.WriteVector32); break;
|
||||
|
||||
case 3: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.WriteVector64Unchecked)
|
||||
: nameof(AMemory.WriteVector64); break;
|
||||
|
||||
case 4: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.WriteVector128Unchecked)
|
||||
: nameof(AMemory.WriteVector128); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case 0: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.WriteByteUnchecked)
|
||||
: nameof(AMemory.WriteByte); break;
|
||||
|
||||
case 1: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.WriteUInt16Unchecked)
|
||||
: nameof(AMemory.WriteUInt16); break;
|
||||
|
||||
case 2: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.WriteUInt32Unchecked)
|
||||
: nameof(AMemory.WriteUInt32); break;
|
||||
|
||||
case 3: Name = AOptimizations.DisableMemoryChecks
|
||||
? nameof(AMemory.WriteUInt64Unchecked)
|
||||
: nameof(AMemory.WriteUInt64); break;
|
||||
}
|
||||
}
|
||||
|
||||
Context.EmitCall(typeof(AMemory), Name);
|
||||
}
|
||||
|
||||
private static bool GetIsSimd(AILEmitterCtx Context)
|
||||
{
|
||||
return Context.CurrOp is IAOpCodeSimd &&
|
||||
!(Context.CurrOp is AOpCodeSimdMemMs ||
|
||||
Context.CurrOp is AOpCodeSimdMemSs);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -101,6 +101,16 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
public static void Fabd_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarBinaryOpF(Context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
EmitUnaryMathCall(Context, nameof(Math.Abs));
|
||||
});
|
||||
}
|
||||
|
||||
public static void Fabs_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarUnaryOpF(Context, () =>
|
||||
|
@ -124,6 +134,11 @@ namespace ChocolArm64.Instruction
|
|||
EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
|
||||
}
|
||||
|
||||
public static void Fdiv_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
|
||||
}
|
||||
|
||||
public static void Fmadd_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarTernaryRaOpF(Context, () =>
|
||||
|
@ -215,6 +230,24 @@ namespace ChocolArm64.Instruction
|
|||
});
|
||||
}
|
||||
|
||||
public static void Fnmsub_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
|
||||
EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
|
||||
|
||||
Context.Emit(OpCodes.Mul);
|
||||
|
||||
EmitVectorExtractF(Context, Op.Ra, 0, SizeF);
|
||||
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, SizeF);
|
||||
}
|
||||
|
||||
public static void Frinta_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
@ -234,6 +267,47 @@ namespace ChocolArm64.Instruction
|
|||
});
|
||||
}
|
||||
|
||||
public static void Frintm_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorUnaryOpF(Context, () =>
|
||||
{
|
||||
EmitUnaryMathCall(Context, nameof(Math.Floor));
|
||||
});
|
||||
}
|
||||
|
||||
public static void Frintp_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarUnaryOpF(Context, () =>
|
||||
{
|
||||
EmitUnaryMathCall(Context, nameof(Math.Ceiling));
|
||||
});
|
||||
}
|
||||
|
||||
public static void Frintx_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
EmitScalarUnaryOpF(Context, () =>
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
|
||||
|
||||
if (Op.Size == 0)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF));
|
||||
}
|
||||
else if (Op.Size == 1)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void Fsqrt_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarUnaryOpF(Context, () =>
|
||||
|
@ -275,6 +349,11 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
|
||||
}
|
||||
|
||||
public static void Mul_Ve(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorBinaryOpByElemZx(Context, () => Context.Emit(OpCodes.Mul));
|
||||
}
|
||||
|
||||
public static void Neg_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
|
||||
|
@ -282,7 +361,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Saddw_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorWidenBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
|
||||
EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
|
||||
}
|
||||
|
||||
public static void Smax_V(AILEmitterCtx Context)
|
||||
|
@ -303,6 +382,20 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
|
||||
}
|
||||
|
||||
public static void Smlal_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorWidenRnRmTernaryOpSx(Context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Mul);
|
||||
Context.Emit(OpCodes.Add);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Smull_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul));
|
||||
}
|
||||
|
||||
public static void Sub_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
|
||||
|
@ -333,7 +426,12 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Uaddw_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorWidenBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
|
||||
EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
|
||||
}
|
||||
|
||||
public static void Umull_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using ChocolArm64.Translation;
|
|||
using System;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
using static ChocolArm64.Instruction.AInstEmitAluHelper;
|
||||
using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
||||
|
||||
namespace ChocolArm64.Instruction
|
||||
|
@ -45,6 +46,45 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorCmp(Context, OpCodes.Blt_S);
|
||||
}
|
||||
|
||||
public static void Cmtst_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));
|
||||
|
||||
for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
|
||||
EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);
|
||||
|
||||
AILLabel LblTrue = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdc_I4(0);
|
||||
|
||||
Context.Emit(OpCodes.Bne_Un_S, LblTrue);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fccmp_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
||||
|
@ -54,24 +94,9 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
Context.EmitCondBranch(LblTrue, Op.Cond);
|
||||
|
||||
//TODO: Share this logic with Ccmp.
|
||||
Context.EmitLdc_I4((Op.NZCV >> 0) & 1);
|
||||
EmitSetNZCV(Context, Op.NZCV);
|
||||
|
||||
Context.EmitStflg((int)APState.VBit);
|
||||
|
||||
Context.EmitLdc_I4((Op.NZCV >> 1) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
|
||||
Context.EmitLdc_I4((Op.NZCV >> 2) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.ZBit);
|
||||
|
||||
Context.EmitLdc_I4((Op.NZCV >> 3) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.NBit);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
Context.Emit(OpCodes.Br, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
|
||||
|
@ -80,12 +105,35 @@ namespace ChocolArm64.Instruction
|
|||
Context.MarkLabel(LblEnd);
|
||||
}
|
||||
|
||||
public static void Fccmpe_S(AILEmitterCtx Context)
|
||||
{
|
||||
Fccmp_S(Context);
|
||||
}
|
||||
|
||||
public static void Fcmp_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false;
|
||||
|
||||
//Handle NaN case. If any number is NaN, then NZCV = 0011.
|
||||
if (CmpWithZero)
|
||||
{
|
||||
EmitNaNCheck(Context, Op.Rn);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitNaNCheck(Context, Op.Rn);
|
||||
EmitNaNCheck(Context, Op.Rm);
|
||||
|
||||
Context.Emit(OpCodes.Or);
|
||||
}
|
||||
|
||||
AILLabel LblNaN = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.Brtrue_S, LblNaN);
|
||||
|
||||
void EmitLoadOpers()
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
|
@ -102,7 +150,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
//Z = Rn == Rm
|
||||
EmitLoadOpers();
|
||||
|
||||
|
||||
Context.Emit(OpCodes.Ceq);
|
||||
Context.Emit(OpCodes.Dup);
|
||||
|
||||
|
@ -123,30 +171,18 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
Context.EmitStflg((int)APState.NBit);
|
||||
|
||||
//Handle NaN case. If any number is NaN, then NZCV = 0011.
|
||||
AILLabel LblNotNaN = new AILLabel();
|
||||
//V = 0
|
||||
Context.EmitLdc_I4(0);
|
||||
|
||||
if (CmpWithZero)
|
||||
{
|
||||
EmitNaNCheck(Context, Op.Rn);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitNaNCheck(Context, Op.Rn);
|
||||
EmitNaNCheck(Context, Op.Rm);
|
||||
|
||||
Context.Emit(OpCodes.Or);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Brfalse_S, LblNotNaN);
|
||||
|
||||
Context.EmitLdc_I4(1);
|
||||
Context.EmitLdc_I4(1);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
Context.EmitStflg((int)APState.VBit);
|
||||
|
||||
Context.MarkLabel(LblNotNaN);
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblNaN);
|
||||
|
||||
EmitSetNZCV(Context, 0b0011);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
}
|
||||
|
||||
public static void Fcmpe_S(AILEmitterCtx Context)
|
|
@ -23,52 +23,127 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Fcvtas_Gp(AILEmitterCtx Context)
|
||||
{
|
||||
Fcvta__Gp(Context, Signed: true);
|
||||
EmitFcvt_s_Gp(Context, () => EmitRoundMathCall(Context, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
public static void Fcvtau_Gp(AILEmitterCtx Context)
|
||||
{
|
||||
Fcvta__Gp(Context, Signed: false);
|
||||
EmitFcvt_u_Gp(Context, () => EmitRoundMathCall(Context, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
public static void Fcvtl_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
int Elems = 4 >> SizeF;
|
||||
|
||||
int Part = Context.CurrOp.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
if (SizeF == 0)
|
||||
{
|
||||
//TODO: This need the half precision floating point type,
|
||||
//that is not yet supported on .NET. We should probably
|
||||
//do our own implementation on the meantime.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, Part + Index, 0);
|
||||
|
||||
Context.Emit(OpCodes.Conv_R8);
|
||||
}
|
||||
|
||||
EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcvtms_Gp(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFcvt_s_Gp(Context, nameof(Math.Floor));
|
||||
EmitFcvt_s_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Floor)));
|
||||
}
|
||||
|
||||
public static void Fcvtmu_Gp(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFcvt_u_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Floor)));
|
||||
}
|
||||
|
||||
public static void Fcvtn_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
int Elems = 4 >> SizeF;
|
||||
|
||||
int Part = Context.CurrOp.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rd, Index, SizeF);
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
//TODO: This need the half precision floating point type,
|
||||
//that is not yet supported on .NET. We should probably
|
||||
//do our own implementation on the meantime.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_R4);
|
||||
|
||||
EmitVectorInsertF(Context, Op.Rd, Part + Index, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcvtps_Gp(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFcvt_s_Gp(Context, nameof(Math.Ceiling));
|
||||
EmitFcvt_s_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Ceiling)));
|
||||
}
|
||||
|
||||
public static void Fcvtpu_Gp(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFcvt_u_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Ceiling)));
|
||||
}
|
||||
|
||||
public static void Fcvtzs_Gp(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFcvtz__Gp(Context, Signed: true);
|
||||
EmitFcvt_s_Gp(Context, () => { });
|
||||
}
|
||||
|
||||
public static void Fcvtzs_Gp_Fix(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFcvtz__Gp_Fix(Context, Signed: true);
|
||||
EmitFcvtzs_Gp_Fix(Context);
|
||||
}
|
||||
|
||||
public static void Fcvtzs_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcvt(Context, Signed: true);
|
||||
EmitVectorFcvtzs(Context);
|
||||
}
|
||||
|
||||
public static void Fcvtzu_Gp(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFcvtz__Gp(Context, Signed: false);
|
||||
EmitFcvt_u_Gp(Context, () => { });
|
||||
}
|
||||
|
||||
public static void Fcvtzu_Gp_Fix(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFcvtz__Gp_Fix(Context, Signed: false);
|
||||
EmitFcvtzu_Gp_Fix(Context);
|
||||
}
|
||||
|
||||
public static void Fcvtzu_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcvt(Context, Signed: false);
|
||||
EmitVectorFcvtzu(Context);
|
||||
}
|
||||
|
||||
public static void Scvtf_Gp(AILEmitterCtx Context)
|
||||
|
@ -91,7 +166,7 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rd, 0, Op.Size + 2);
|
||||
EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size + 2);
|
||||
|
||||
EmitFloatCast(Context, Op.Size);
|
||||
|
||||
|
@ -165,13 +240,23 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
private static void Fcvta__Gp(AILEmitterCtx Context, bool Signed)
|
||||
private static void EmitFcvt_s_Gp(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitFcvt___Gp(Context, Emit, true);
|
||||
}
|
||||
|
||||
private static void EmitFcvt_u_Gp(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitFcvt___Gp(Context, Emit, false);
|
||||
}
|
||||
|
||||
private static void EmitFcvt___Gp(AILEmitterCtx Context, Action Emit, bool Signed)
|
||||
{
|
||||
AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
|
||||
EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
|
||||
Emit();
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
|
@ -190,45 +275,14 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitFcvt_s_Gp(AILEmitterCtx Context, string Name)
|
||||
private static void EmitFcvtzs_Gp_Fix(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
|
||||
EmitUnaryMathCall(Context, Name);
|
||||
|
||||
EmitScalarFcvts(Context, Op.Size, 0);
|
||||
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
EmitFcvtz__Gp_Fix(Context, true);
|
||||
}
|
||||
|
||||
private static void EmitFcvtz__Gp(AILEmitterCtx Context, bool Signed)
|
||||
private static void EmitFcvtzu_Gp_Fix(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
EmitScalarFcvts(Context, Op.Size, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarFcvtu(Context, Op.Size, 0);
|
||||
}
|
||||
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
EmitFcvtz__Gp_Fix(Context, false);
|
||||
}
|
||||
|
||||
private static void EmitFcvtz__Gp_Fix(AILEmitterCtx Context, bool Signed)
|
||||
|
@ -254,6 +308,16 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitVectorScvtf(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorCvtf(Context, true);
|
||||
}
|
||||
|
||||
private static void EmitVectorUcvtf(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorCvtf(Context, false);
|
||||
}
|
||||
|
||||
private static void EmitVectorCvtf(AILEmitterCtx Context, bool Signed)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
@ -289,7 +353,17 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorFcvt(AILEmitterCtx Context, bool Signed)
|
||||
private static void EmitVectorFcvtzs(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcvtz(Context, true);
|
||||
}
|
||||
|
||||
private static void EmitVectorFcvtzu(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcvtz(Context, false);
|
||||
}
|
||||
|
||||
private static void EmitVectorFcvtz(AILEmitterCtx Context, bool Signed)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
|
@ -36,20 +36,18 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
MethodInfo MthdInfo;
|
||||
|
||||
if (Op.Size == 0)
|
||||
if (SizeF == 0)
|
||||
{
|
||||
MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float) });
|
||||
}
|
||||
else if (Op.Size == 1)
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double) });
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Context.EmitCall(MthdInfo);
|
||||
}
|
||||
|
@ -58,20 +56,18 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
MethodInfo MthdInfo;
|
||||
|
||||
if (Op.Size == 0)
|
||||
if (SizeF == 0)
|
||||
{
|
||||
MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float), typeof(float) });
|
||||
}
|
||||
else if (Op.Size == 1)
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double), typeof(double) });
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Context.EmitCall(MthdInfo);
|
||||
}
|
||||
|
@ -80,28 +76,26 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
Context.EmitLdc_I4((int)RoundMode);
|
||||
|
||||
MethodInfo MthdInfo;
|
||||
|
||||
Type[] Types = new Type[] { null, typeof(MidpointRounding) };
|
||||
|
||||
Types[0] = Op.Size == 0
|
||||
Types[0] = SizeF == 0
|
||||
? typeof(float)
|
||||
: typeof(double);
|
||||
|
||||
if (Op.Size == 0)
|
||||
if (SizeF == 0)
|
||||
{
|
||||
MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types);
|
||||
}
|
||||
else if (Op.Size == 1)
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Context.EmitCall(MthdInfo);
|
||||
}
|
||||
|
@ -133,7 +127,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitScalarOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
if (Opers.HasFlag(OperFlags.Rd))
|
||||
{
|
||||
|
@ -147,7 +141,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (Opers.HasFlag(OperFlags.Rm))
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rm, 0, Op.Size, Signed);
|
||||
EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, 0, Op.Size, Signed);
|
||||
}
|
||||
|
||||
Emit();
|
||||
|
@ -196,6 +190,11 @@ namespace ChocolArm64.Instruction
|
|||
EmitScalarSetF(Context, Op.Rd, SizeF);
|
||||
}
|
||||
|
||||
public static void EmitVectorUnaryOpF(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitVectorOpF(Context, Emit, OperFlags.Rn);
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpF(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitVectorOpF(Context, Emit, OperFlags.RnRm);
|
||||
|
@ -206,23 +205,9 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorOpF(Context, Emit, OperFlags.RdRnRm);
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpByElemF(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
|
||||
|
||||
EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: false);
|
||||
}
|
||||
|
||||
public static void EmitVectorTernaryOpByElemF(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
|
||||
|
||||
EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: true);
|
||||
}
|
||||
|
||||
public static void EmitVectorOpF(AILEmitterCtx Context, Action Emit, OperFlags Opers)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
|
@ -242,7 +227,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (Opers.HasFlag(OperFlags.Rm))
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
|
||||
EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Rm, Index, SizeF);
|
||||
}
|
||||
|
||||
Emit();
|
||||
|
@ -256,6 +241,20 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpByElemF(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
AOpCodeSimdRegElemF Op = (AOpCodeSimdRegElemF)Context.CurrOp;
|
||||
|
||||
EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: false);
|
||||
}
|
||||
|
||||
public static void EmitVectorTernaryOpByElemF(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
AOpCodeSimdRegElemF Op = (AOpCodeSimdRegElemF)Context.CurrOp;
|
||||
|
||||
EmitVectorOpByElemF(Context, Emit, Op.Index, Ternary: true);
|
||||
}
|
||||
|
||||
public static void EmitVectorOpByElemF(AILEmitterCtx Context, Action Emit, int Elem, bool Ternary)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
@ -347,6 +346,54 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpByElemSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
|
||||
|
||||
EmitVectorOpByElem(Context, Emit, Op.Index, false, true);
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpByElemZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
|
||||
|
||||
EmitVectorOpByElem(Context, Emit, Op.Index, false, false);
|
||||
}
|
||||
|
||||
public static void EmitVectorTernaryOpByElemZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
|
||||
|
||||
EmitVectorOpByElem(Context, Emit, Op.Index, true, false);
|
||||
}
|
||||
|
||||
public static void EmitVectorOpByElem(AILEmitterCtx Context, Action Emit, int Elem, bool Ternary, bool Signed)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
|
||||
{
|
||||
if (Ternary)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed);
|
||||
}
|
||||
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
|
||||
EmitVectorExtract(Context, Op.Rm, Index, Op.Size, Signed);
|
||||
|
||||
Emit();
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorImmUnaryOp(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitVectorImmOp(Context, Emit, false);
|
||||
|
@ -383,17 +430,17 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorWidenBinaryOpSx(AILEmitterCtx Context, Action Emit)
|
||||
public static void EmitVectorWidenRmBinaryOpSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitVectorWidenBinaryOp(Context, Emit, true);
|
||||
EmitVectorWidenRmBinaryOp(Context, Emit, true);
|
||||
}
|
||||
|
||||
public static void EmitVectorWidenBinaryOpZx(AILEmitterCtx Context, Action Emit)
|
||||
public static void EmitVectorWidenRmBinaryOpZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitVectorWidenBinaryOp(Context, Emit, false);
|
||||
EmitVectorWidenRmBinaryOp(Context, Emit, false);
|
||||
}
|
||||
|
||||
public static void EmitVectorWidenBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed)
|
||||
public static void EmitVectorWidenRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
|
@ -415,6 +462,53 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitStvec(Op.Rd);
|
||||
}
|
||||
|
||||
public static void EmitVectorWidenRnRmBinaryOpSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitVectorWidenRnRmOp(Context, Emit, false, true);
|
||||
}
|
||||
|
||||
public static void EmitVectorWidenRnRmBinaryOpZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitVectorWidenRnRmOp(Context, Emit, false, false);
|
||||
}
|
||||
|
||||
public static void EmitVectorWidenRnRmTernaryOpSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitVectorWidenRnRmOp(Context, Emit, true, true);
|
||||
}
|
||||
|
||||
public static void EmitVectorWidenRnRmTernaryOpZx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitVectorWidenRnRmOp(Context, Emit, true, false);
|
||||
}
|
||||
|
||||
public static void EmitVectorWidenRnRmOp(AILEmitterCtx Context, Action Emit, bool Ternary, bool Signed)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int Elems = 8 >> Op.Size;
|
||||
|
||||
int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
if (Ternary)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rd, Index, Op.Size + 1, Signed);
|
||||
}
|
||||
|
||||
EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed);
|
||||
EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed);
|
||||
|
||||
Emit();
|
||||
|
||||
EmitVectorInsertTmp(Context, Index, Op.Size + 1);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
}
|
||||
|
||||
public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size)
|
||||
{
|
||||
EmitVectorZeroAll(Context, Reg);
|
|
@ -1,3 +1,5 @@
|
|||
using ChocolArm64.Decoder;
|
||||
using ChocolArm64.State;
|
||||
using ChocolArm64.Translation;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
|
@ -65,5 +67,28 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or));
|
||||
}
|
||||
|
||||
public static void Rev64_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
int Elems = Bytes >> Op.Size;
|
||||
|
||||
int RevIndex = Elems - 1;
|
||||
|
||||
for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rn, RevIndex--, Op.Size);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,6 +57,34 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
public static void Ext_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdExt Op = (AOpCodeSimdExt)Context.CurrOp;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
int Position = Op.Imm4;
|
||||
|
||||
for (int Index = 0; Index < Bytes; Index++)
|
||||
{
|
||||
int Reg = Op.Imm4 + Index < Bytes ? Op.Rn : Op.Rm;
|
||||
|
||||
if (Position == Bytes)
|
||||
{
|
||||
Position = 0;
|
||||
}
|
||||
|
||||
EmitVectorExtractZx(Context, Reg, Position++, 0);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, 0);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcsel_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
||||
|
@ -263,6 +291,16 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
public static void Zip1_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorZip(Context, Part: 0);
|
||||
}
|
||||
|
||||
public static void Zip2_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorZip(Context, Part: 1);
|
||||
}
|
||||
|
||||
private static void EmitIntZeroHigherIfNeeded(AILEmitterCtx Context)
|
||||
{
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
|
@ -295,5 +333,29 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorZip(AILEmitterCtx Context, int Part)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
int Elems = Bytes >> Op.Size;
|
||||
int Half = Elems >> 1;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
int Elem = Part * Half + (Index >> 1);
|
||||
|
||||
EmitVectorExtractZx(Context, (Index & 1) == 0 ? Op.Rn : Op.Rm, Elem, Op.Size);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,15 +10,6 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
static partial class AInstEmit
|
||||
{
|
||||
[Flags]
|
||||
private enum ShrFlags
|
||||
{
|
||||
None = 0,
|
||||
Signed = 1 << 0,
|
||||
Rounding = 1 << 1,
|
||||
Accumulate = 1 << 2
|
||||
}
|
||||
|
||||
public static void Shl_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
@ -38,7 +29,16 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
int Shift = Op.Imm - (8 << Op.Size);
|
||||
|
||||
EmitVectorShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
|
||||
EmitVectorBinaryShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
|
||||
}
|
||||
|
||||
public static void Shll_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int Shift = 8 << Op.Size;
|
||||
|
||||
EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
|
||||
}
|
||||
|
||||
public static void Shrn_V(AILEmitterCtx Context)
|
||||
|
@ -83,7 +83,22 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
int Shift = (8 << (Op.Size + 1)) - Op.Imm;
|
||||
|
||||
EmitVectorShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift);
|
||||
EmitVectorBinaryShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift);
|
||||
}
|
||||
|
||||
public static void Ssra_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
int Shift = (8 << (Op.Size + 1)) - Op.Imm;
|
||||
|
||||
Action Emit = () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Shr);
|
||||
Context.Emit(OpCodes.Add);
|
||||
};
|
||||
|
||||
EmitVectorTernaryShImmBinarySx(Context, Emit, Shift);
|
||||
}
|
||||
|
||||
public static void Ushl_V(AILEmitterCtx Context)
|
||||
|
@ -100,14 +115,43 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
|
||||
}
|
||||
|
||||
public static void Ushr_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
EmitScalarUnaryOpZx(Context, () =>
|
||||
{
|
||||
Context.EmitLdc_I4(GetImmShr(Op));
|
||||
|
||||
Context.Emit(OpCodes.Shr_Un);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Ushr_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorShr(Context, ShrFlags.None);
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
EmitVectorUnaryOpZx(Context, () =>
|
||||
{
|
||||
Context.EmitLdc_I4(GetImmShr(Op));
|
||||
|
||||
Context.Emit(OpCodes.Shr_Un);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Usra_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorShr(Context, ShrFlags.Accumulate);
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
Action Emit = () =>
|
||||
{
|
||||
Context.EmitLdc_I4(GetImmShr(Op));
|
||||
|
||||
Context.Emit(OpCodes.Shr_Un);
|
||||
Context.Emit(OpCodes.Add);
|
||||
};
|
||||
|
||||
EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false);
|
||||
}
|
||||
|
||||
private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
|
||||
|
@ -173,53 +217,34 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorShr(AILEmitterCtx Context, ShrFlags Flags)
|
||||
private static void EmitVectorBinaryShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
int Shift = (8 << (Op.Size + 1)) - Op.Imm;
|
||||
|
||||
if (Flags.HasFlag(ShrFlags.Accumulate))
|
||||
{
|
||||
Action Emit = () =>
|
||||
{
|
||||
Context.EmitLdc_I4(Shift);
|
||||
|
||||
Context.Emit(OpCodes.Shr_Un);
|
||||
Context.Emit(OpCodes.Add);
|
||||
};
|
||||
|
||||
EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorUnaryOpZx(Context, () =>
|
||||
{
|
||||
Context.EmitLdc_I4(Shift);
|
||||
|
||||
Context.Emit(OpCodes.Shr_Un);
|
||||
});
|
||||
}
|
||||
EmitVectorShImmBinaryOp(Context, Emit, Imm, false, true);
|
||||
}
|
||||
|
||||
private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
|
||||
private static void EmitVectorTernaryShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
|
||||
{
|
||||
EmitVectorShImmBinaryOp(Context, Emit, Imm, true);
|
||||
EmitVectorShImmBinaryOp(Context, Emit, Imm, true, true);
|
||||
}
|
||||
|
||||
private static void EmitVectorShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
|
||||
private static void EmitVectorBinaryShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
|
||||
{
|
||||
EmitVectorShImmBinaryOp(Context, Emit, Imm, false);
|
||||
EmitVectorShImmBinaryOp(Context, Emit, Imm, false, false);
|
||||
}
|
||||
|
||||
private static void EmitVectorShImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
|
||||
private static void EmitVectorShImmBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Ternary, bool Signed)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
|
||||
{
|
||||
if (Ternary)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed);
|
||||
}
|
||||
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
|
||||
|
||||
Context.EmitLdc_I4(Imm);
|
||||
|
@ -247,7 +272,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int Elems = 8 >> Op.Size;
|
||||
|
||||
|
@ -282,7 +307,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
|
||||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int Elems = 8 >> Op.Size;
|
||||
|
|
@ -9,6 +9,11 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
static partial class AInstEmit
|
||||
{
|
||||
public static void Hint(AILEmitterCtx Context)
|
||||
{
|
||||
//Execute as no-op.
|
||||
}
|
||||
|
||||
public static void Mrs(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
|
|
@ -1,6 +1,7 @@
|
|||
using ChocolArm64.State;
|
||||
using ChocolArm64.Translation;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ChocolArm64.Instruction
|
||||
|
@ -74,7 +75,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
private static ulong ReverseBytes(ulong Value, RevSize Size)
|
||||
{
|
||||
Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8);
|
||||
Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8);
|
||||
|
||||
if (Size == RevSize.Rev16)
|
||||
{
|
||||
|
@ -101,6 +102,8 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int SatF32ToS32(float Value)
|
||||
{
|
||||
if (float.IsNaN(Value)) return 0;
|
||||
|
||||
return Value > int.MaxValue ? int.MaxValue :
|
||||
Value < int.MinValue ? int.MinValue : (int)Value;
|
||||
}
|
||||
|
@ -108,6 +111,8 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long SatF32ToS64(float Value)
|
||||
{
|
||||
if (float.IsNaN(Value)) return 0;
|
||||
|
||||
return Value > long.MaxValue ? long.MaxValue :
|
||||
Value < long.MinValue ? long.MinValue : (long)Value;
|
||||
}
|
||||
|
@ -115,6 +120,8 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint SatF32ToU32(float Value)
|
||||
{
|
||||
if (float.IsNaN(Value)) return 0;
|
||||
|
||||
return Value > uint.MaxValue ? uint.MaxValue :
|
||||
Value < uint.MinValue ? uint.MinValue : (uint)Value;
|
||||
}
|
||||
|
@ -122,6 +129,8 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong SatF32ToU64(float Value)
|
||||
{
|
||||
if (float.IsNaN(Value)) return 0;
|
||||
|
||||
return Value > ulong.MaxValue ? ulong.MaxValue :
|
||||
Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
|
||||
}
|
||||
|
@ -129,6 +138,8 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int SatF64ToS32(double Value)
|
||||
{
|
||||
if (double.IsNaN(Value)) return 0;
|
||||
|
||||
return Value > int.MaxValue ? int.MaxValue :
|
||||
Value < int.MinValue ? int.MinValue : (int)Value;
|
||||
}
|
||||
|
@ -136,6 +147,8 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long SatF64ToS64(double Value)
|
||||
{
|
||||
if (double.IsNaN(Value)) return 0;
|
||||
|
||||
return Value > long.MaxValue ? long.MaxValue :
|
||||
Value < long.MinValue ? long.MinValue : (long)Value;
|
||||
}
|
||||
|
@ -143,6 +156,8 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint SatF64ToU32(double Value)
|
||||
{
|
||||
if (double.IsNaN(Value)) return 0;
|
||||
|
||||
return Value > uint.MaxValue ? uint.MaxValue :
|
||||
Value < uint.MinValue ? uint.MinValue : (uint)Value;
|
||||
}
|
||||
|
@ -150,46 +165,20 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong SatF64ToU64(double Value)
|
||||
{
|
||||
if (double.IsNaN(Value)) return 0;
|
||||
|
||||
return Value > ulong.MaxValue ? ulong.MaxValue :
|
||||
Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
|
||||
}
|
||||
|
||||
public static ulong SMulHi128(ulong LHS, ulong RHS)
|
||||
public static long SMulHi128(long LHS, long RHS)
|
||||
{
|
||||
long LLo = (uint)(LHS >> 0);
|
||||
long LHi = (int)(LHS >> 32);
|
||||
long RLo = (uint)(RHS >> 0);
|
||||
long RHi = (int)(RHS >> 32);
|
||||
|
||||
long LHiRHi = LHi * RHi;
|
||||
long LHiRLo = LHi * RLo;
|
||||
long LLoRHi = LLo * RHi;
|
||||
long LLoRLo = LLo * RLo;
|
||||
|
||||
long Carry = ((uint)LHiRLo + ((uint)LLoRHi + (LLoRLo >> 32))) >> 32;
|
||||
|
||||
long ResHi = LHiRHi + (LHiRLo >> 32) + (LLoRHi >> 32) + Carry;
|
||||
|
||||
return (ulong)ResHi;
|
||||
return (long)(BigInteger.Multiply(LHS, RHS) >> 64);
|
||||
}
|
||||
|
||||
public static ulong UMulHi128(ulong LHS, ulong RHS)
|
||||
{
|
||||
ulong LLo = (uint)(LHS >> 0);
|
||||
ulong LHi = (uint)(LHS >> 32);
|
||||
ulong RLo = (uint)(RHS >> 0);
|
||||
ulong RHi = (uint)(RHS >> 32);
|
||||
|
||||
ulong LHiRHi = LHi * RHi;
|
||||
ulong LHiRLo = LHi * RLo;
|
||||
ulong LLoRHi = LLo * RHi;
|
||||
ulong LLoRLo = LLo * RLo;
|
||||
|
||||
ulong Carry = ((uint)LHiRLo + ((uint)LLoRHi + (LLoRLo >> 32))) >> 32;
|
||||
|
||||
ulong ResHi = LHiRHi + (LHiRLo >> 32) + (LLoRHi >> 32) + Carry;
|
||||
|
||||
return ResHi;
|
||||
return (ulong)(BigInteger.Multiply(LHS, RHS) >> 64);
|
||||
}
|
||||
|
||||
public static int CountSetBits8(byte Value)
|
||||
|
@ -200,6 +189,32 @@ namespace ChocolArm64.Instruction
|
|||
(Value >> 6) & 1 + (Value >> 7);
|
||||
}
|
||||
|
||||
public static float RoundF(float Value, int Fpcr)
|
||||
{
|
||||
switch ((ARoundMode)((Fpcr >> 22) & 3))
|
||||
{
|
||||
case ARoundMode.ToNearest: return MathF.Round (Value);
|
||||
case ARoundMode.TowardsPlusInfinity: return MathF.Ceiling (Value);
|
||||
case ARoundMode.TowardsMinusInfinity: return MathF.Floor (Value);
|
||||
case ARoundMode.TowardsZero: return MathF.Truncate(Value);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public static double Round(double Value, int Fpcr)
|
||||
{
|
||||
switch ((ARoundMode)((Fpcr >> 22) & 3))
|
||||
{
|
||||
case ARoundMode.ToNearest: return Math.Round (Value);
|
||||
case ARoundMode.TowardsPlusInfinity: return Math.Ceiling (Value);
|
||||
case ARoundMode.TowardsMinusInfinity: return Math.Floor (Value);
|
||||
case ARoundMode.TowardsZero: return Math.Truncate(Value);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public static AVec Tbl1_V64(AVec Vector, AVec Tb0)
|
||||
{
|
||||
return Tbl(Vector, 8, Tb0);
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Exceptions;
|
|||
using ChocolArm64.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ChocolArm64.Memory
|
||||
{
|
||||
public unsafe class AMemory
|
||||
public unsafe class AMemory : IDisposable
|
||||
{
|
||||
private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1;
|
||||
|
||||
|
@ -39,16 +39,20 @@ namespace ChocolArm64.Memory
|
|||
|
||||
private HashSet<long> ExAddrs;
|
||||
|
||||
public IntPtr Ram { get; private set; }
|
||||
|
||||
private byte* RamPtr;
|
||||
|
||||
public AMemory(IntPtr Ram, AMemoryAlloc Allocator)
|
||||
public AMemory()
|
||||
{
|
||||
Manager = new AMemoryMgr(Allocator);
|
||||
Manager = new AMemoryMgr();
|
||||
|
||||
Monitors = new Dictionary<int, ExMonitor>();
|
||||
|
||||
ExAddrs = new HashSet<long>();
|
||||
|
||||
Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize + AMemoryMgr.PageSize);
|
||||
|
||||
RamPtr = (byte*)Ram;
|
||||
}
|
||||
|
||||
|
@ -134,98 +138,79 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
public sbyte ReadSByte(long Position) => (sbyte)ReadByte (Position);
|
||||
public short ReadInt16(long Position) => (short)ReadUInt16(Position);
|
||||
public int ReadInt32(long Position) => (int)ReadUInt32(Position);
|
||||
public long ReadInt64(long Position) => (long)ReadUInt64(Position);
|
||||
public sbyte ReadSByte(long Position)
|
||||
{
|
||||
return (sbyte)ReadByte(Position);
|
||||
}
|
||||
|
||||
public short ReadInt16(long Position)
|
||||
{
|
||||
return (short)ReadUInt16(Position);
|
||||
}
|
||||
|
||||
public int ReadInt32(long Position)
|
||||
{
|
||||
return (int)ReadUInt32(Position);
|
||||
}
|
||||
|
||||
public long ReadInt64(long Position)
|
||||
{
|
||||
return (long)ReadUInt64(Position);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public byte ReadByte(long Position)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||
#endif
|
||||
|
||||
return *((byte*)(RamPtr + (uint)Position));
|
||||
return ReadByteUnchecked(Position);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ushort ReadUInt16(long Position)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||
#endif
|
||||
EnsureAccessIsValid(Position + 0, AMemoryPerm.Read);
|
||||
EnsureAccessIsValid(Position + 1, AMemoryPerm.Read);
|
||||
|
||||
return *((ushort*)(RamPtr + (uint)Position));
|
||||
return ReadUInt16Unchecked(Position);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint ReadUInt32(long Position)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||
#endif
|
||||
EnsureAccessIsValid(Position + 0, AMemoryPerm.Read);
|
||||
EnsureAccessIsValid(Position + 3, AMemoryPerm.Read);
|
||||
|
||||
return *((uint*)(RamPtr + (uint)Position));
|
||||
return ReadUInt32Unchecked(Position);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ulong ReadUInt64(long Position)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||
#endif
|
||||
EnsureAccessIsValid(Position + 0, AMemoryPerm.Read);
|
||||
EnsureAccessIsValid(Position + 7, AMemoryPerm.Read);
|
||||
|
||||
return *((ulong*)(RamPtr + (uint)Position));
|
||||
return ReadUInt64Unchecked(Position);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public AVec ReadVector8(long Position)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||
#endif
|
||||
|
||||
return new AVec() { B0 = ReadByte(Position) };
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public AVec ReadVector16(long Position)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||
#endif
|
||||
|
||||
return new AVec() { H0 = ReadUInt16(Position) };
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public AVec ReadVector32(long Position)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||
#endif
|
||||
|
||||
return new AVec() { W0 = ReadUInt32(Position) };
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public AVec ReadVector64(long Position)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||
#endif
|
||||
|
||||
return new AVec() { X0 = ReadUInt64(Position) };
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public AVec ReadVector128(long Position)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||
#endif
|
||||
|
||||
return new AVec()
|
||||
{
|
||||
X0 = ReadUInt64(Position + 0),
|
||||
|
@ -233,102 +218,218 @@ namespace ChocolArm64.Memory
|
|||
};
|
||||
}
|
||||
|
||||
public void WriteSByte(long Position, sbyte Value) => WriteByte (Position, (byte)Value);
|
||||
public void WriteInt16(long Position, short Value) => WriteUInt16(Position, (ushort)Value);
|
||||
public void WriteInt32(long Position, int Value) => WriteUInt32(Position, (uint)Value);
|
||||
public void WriteInt64(long Position, long Value) => WriteUInt64(Position, (ulong)Value);
|
||||
public sbyte ReadSByteUnchecked(long Position)
|
||||
{
|
||||
return (sbyte)ReadByteUnchecked(Position);
|
||||
}
|
||||
|
||||
public short ReadInt16Unchecked(long Position)
|
||||
{
|
||||
return (short)ReadUInt16Unchecked(Position);
|
||||
}
|
||||
|
||||
public int ReadInt32Unchecked(long Position)
|
||||
{
|
||||
return (int)ReadUInt32Unchecked(Position);
|
||||
}
|
||||
|
||||
public long ReadInt64Unchecked(long Position)
|
||||
{
|
||||
return (long)ReadUInt64Unchecked(Position);
|
||||
}
|
||||
|
||||
public byte ReadByteUnchecked(long Position)
|
||||
{
|
||||
return *((byte*)(RamPtr + (uint)Position));
|
||||
}
|
||||
|
||||
public ushort ReadUInt16Unchecked(long Position)
|
||||
{
|
||||
return *((ushort*)(RamPtr + (uint)Position));
|
||||
}
|
||||
|
||||
public uint ReadUInt32Unchecked(long Position)
|
||||
{
|
||||
return *((uint*)(RamPtr + (uint)Position));
|
||||
}
|
||||
|
||||
public ulong ReadUInt64Unchecked(long Position)
|
||||
{
|
||||
return *((ulong*)(RamPtr + (uint)Position));
|
||||
}
|
||||
|
||||
public AVec ReadVector8Unchecked(long Position)
|
||||
{
|
||||
return new AVec() { B0 = ReadByteUnchecked(Position) };
|
||||
}
|
||||
|
||||
public AVec ReadVector16Unchecked(long Position)
|
||||
{
|
||||
return new AVec() { H0 = ReadUInt16Unchecked(Position) };
|
||||
}
|
||||
|
||||
public AVec ReadVector32Unchecked(long Position)
|
||||
{
|
||||
return new AVec() { W0 = ReadUInt32Unchecked(Position) };
|
||||
}
|
||||
|
||||
public AVec ReadVector64Unchecked(long Position)
|
||||
{
|
||||
return new AVec() { X0 = ReadUInt64Unchecked(Position) };
|
||||
}
|
||||
|
||||
public AVec ReadVector128Unchecked(long Position)
|
||||
{
|
||||
return new AVec()
|
||||
{
|
||||
X0 = ReadUInt64Unchecked(Position + 0),
|
||||
X1 = ReadUInt64Unchecked(Position + 8)
|
||||
};
|
||||
}
|
||||
|
||||
public void WriteSByte(long Position, sbyte Value)
|
||||
{
|
||||
WriteByte(Position, (byte)Value);
|
||||
}
|
||||
|
||||
public void WriteInt16(long Position, short Value)
|
||||
{
|
||||
WriteUInt16(Position, (ushort)Value);
|
||||
}
|
||||
|
||||
public void WriteInt32(long Position, int Value)
|
||||
{
|
||||
WriteUInt32(Position, (uint)Value);
|
||||
}
|
||||
|
||||
public void WriteInt64(long Position, long Value)
|
||||
{
|
||||
WriteUInt64(Position, (ulong)Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteByte(long Position, byte Value)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||
#endif
|
||||
|
||||
*((byte*)(RamPtr + (uint)Position)) = Value;
|
||||
WriteByteUnchecked(Position, Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteUInt16(long Position, ushort Value)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||
#endif
|
||||
EnsureAccessIsValid(Position + 0, AMemoryPerm.Write);
|
||||
EnsureAccessIsValid(Position + 1, AMemoryPerm.Write);
|
||||
|
||||
*((ushort*)(RamPtr + (uint)Position)) = Value;
|
||||
WriteUInt16Unchecked(Position, Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteUInt32(long Position, uint Value)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||
#endif
|
||||
EnsureAccessIsValid(Position + 0, AMemoryPerm.Write);
|
||||
EnsureAccessIsValid(Position + 3, AMemoryPerm.Write);
|
||||
|
||||
*((uint*)(RamPtr + (uint)Position)) = Value;
|
||||
WriteUInt32Unchecked(Position, Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteUInt64(long Position, ulong Value)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||
#endif
|
||||
EnsureAccessIsValid(Position + 0, AMemoryPerm.Write);
|
||||
EnsureAccessIsValid(Position + 7, AMemoryPerm.Write);
|
||||
|
||||
*((ulong*)(RamPtr + (uint)Position)) = Value;
|
||||
WriteUInt64Unchecked(Position, Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector8(long Position, AVec Value)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||
#endif
|
||||
|
||||
WriteByte(Position, Value.B0);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector16(long Position, AVec Value)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||
#endif
|
||||
|
||||
WriteUInt16(Position, Value.H0);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector32(long Position, AVec Value)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||
#endif
|
||||
|
||||
WriteUInt32(Position, Value.W0);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector64(long Position, AVec Value)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||
#endif
|
||||
|
||||
WriteUInt64(Position, Value.X0);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector128(long Position, AVec Value)
|
||||
{
|
||||
#if DEBUG
|
||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||
#endif
|
||||
|
||||
WriteUInt64(Position + 0, Value.X0);
|
||||
WriteUInt64(Position + 8, Value.X1);
|
||||
}
|
||||
|
||||
public void WriteSByteUnchecked(long Position, sbyte Value)
|
||||
{
|
||||
WriteByteUnchecked(Position, (byte)Value);
|
||||
}
|
||||
|
||||
public void WriteInt16Unchecked(long Position, short Value)
|
||||
{
|
||||
WriteUInt16Unchecked(Position, (ushort)Value);
|
||||
}
|
||||
|
||||
public void WriteInt32Unchecked(long Position, int Value)
|
||||
{
|
||||
WriteUInt32Unchecked(Position, (uint)Value);
|
||||
}
|
||||
|
||||
public void WriteInt64Unchecked(long Position, long Value)
|
||||
{
|
||||
WriteUInt64Unchecked(Position, (ulong)Value);
|
||||
}
|
||||
|
||||
public void WriteByteUnchecked(long Position, byte Value)
|
||||
{
|
||||
*((byte*)(RamPtr + (uint)Position)) = Value;
|
||||
}
|
||||
|
||||
public void WriteUInt16Unchecked(long Position, ushort Value)
|
||||
{
|
||||
*((ushort*)(RamPtr + (uint)Position)) = Value;
|
||||
}
|
||||
|
||||
public void WriteUInt32Unchecked(long Position, uint Value)
|
||||
{
|
||||
*((uint*)(RamPtr + (uint)Position)) = Value;
|
||||
}
|
||||
|
||||
public void WriteUInt64Unchecked(long Position, ulong Value)
|
||||
{
|
||||
*((ulong*)(RamPtr + (uint)Position)) = Value;
|
||||
}
|
||||
|
||||
public void WriteVector8Unchecked(long Position, AVec Value)
|
||||
{
|
||||
WriteByteUnchecked(Position, Value.B0);
|
||||
}
|
||||
|
||||
public void WriteVector16Unchecked(long Position, AVec Value)
|
||||
{
|
||||
WriteUInt16Unchecked(Position, Value.H0);
|
||||
}
|
||||
|
||||
public void WriteVector32Unchecked(long Position, AVec Value)
|
||||
{
|
||||
WriteUInt32Unchecked(Position, Value.W0);
|
||||
}
|
||||
|
||||
public void WriteVector64Unchecked(long Position, AVec Value)
|
||||
{
|
||||
WriteUInt64Unchecked(Position, Value.X0);
|
||||
}
|
||||
|
||||
public void WriteVector128Unchecked(long Position, AVec Value)
|
||||
{
|
||||
WriteUInt64Unchecked(Position + 0, Value.X0);
|
||||
WriteUInt64Unchecked(Position + 8, Value.X1);
|
||||
}
|
||||
|
||||
private void EnsureAccessIsValid(long Position, AMemoryPerm Perm)
|
||||
{
|
||||
if (!Manager.IsMapped(Position))
|
||||
|
@ -341,5 +442,20 @@ namespace ChocolArm64.Memory
|
|||
throw new VmmAccessViolationException(Position, Perm);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Ram != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(Ram);
|
||||
|
||||
Ram = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue