commit
a3ce90a23d
347 changed files with 9659 additions and 4749 deletions
|
@ -26,6 +26,10 @@
|
||||||
|
|
||||||
Enable the Fatal Logging (Enabled in Debug recommanded).
|
Enable the Fatal Logging (Enabled in Debug recommanded).
|
||||||
|
|
||||||
|
- `Logging_Enable_Ipc` *(bool)*
|
||||||
|
|
||||||
|
Enable the Ipc Message Logging.
|
||||||
|
|
||||||
- `Logging_Enable_LogFile` *(bool)*
|
- `Logging_Enable_LogFile` *(bool)*
|
||||||
|
|
||||||
Enable writing the logging inside a Ryujinx.log file.
|
Enable writing the logging inside a Ryujinx.log file.
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace ChocolArm64
|
||||||
#region "OpCode Table"
|
#region "OpCode Table"
|
||||||
//Integer
|
//Integer
|
||||||
Set("x0011010000xxxxx000000xxxxxxxxxx", AInstEmit.Adc, typeof(AOpCodeAluRs));
|
Set("x0011010000xxxxx000000xxxxxxxxxx", AInstEmit.Adc, typeof(AOpCodeAluRs));
|
||||||
|
Set("x0111010000xxxxx000000xxxxxxxxxx", AInstEmit.Adcs, typeof(AOpCodeAluRs));
|
||||||
Set("x00100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluImm));
|
Set("x00100010xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluImm));
|
||||||
Set("x0001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRs));
|
Set("x0001011<<0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRs));
|
||||||
Set("x0001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRx));
|
Set("x0001011001xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Add, typeof(AOpCodeAluRx));
|
||||||
|
@ -47,9 +48,11 @@ namespace ChocolArm64
|
||||||
Set("x1011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csneg, typeof(AOpCodeCsel));
|
Set("x1011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csneg, typeof(AOpCodeCsel));
|
||||||
Set("11010101000000110011xxxx10111111", AInstEmit.Dmb, typeof(AOpCodeSystem));
|
Set("11010101000000110011xxxx10111111", AInstEmit.Dmb, typeof(AOpCodeSystem));
|
||||||
Set("11010101000000110011xxxx10011111", AInstEmit.Dsb, typeof(AOpCodeSystem));
|
Set("11010101000000110011xxxx10011111", AInstEmit.Dsb, typeof(AOpCodeSystem));
|
||||||
|
Set("x1001010xx1xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eon, typeof(AOpCodeAluRs));
|
||||||
Set("x10100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluImm));
|
Set("x10100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluImm));
|
||||||
Set("x1001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluRs));
|
Set("x1001010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Eor, typeof(AOpCodeAluRs));
|
||||||
Set("x00100111x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Extr, typeof(AOpCodeAluRs));
|
Set("x00100111x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Extr, typeof(AOpCodeAluRs));
|
||||||
|
Set("11010101000000110010xxxxxxx11111", AInstEmit.Hint, typeof(AOpCodeSystem));
|
||||||
Set("xx001000110xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldar, typeof(AOpCodeMemEx));
|
Set("xx001000110xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldar, typeof(AOpCodeMemEx));
|
||||||
Set("1x001000011xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxp, typeof(AOpCodeMemEx));
|
Set("1x001000011xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxp, typeof(AOpCodeMemEx));
|
||||||
Set("xx001000010xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxr, typeof(AOpCodeMemEx));
|
Set("xx001000010xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Ldaxr, typeof(AOpCodeMemEx));
|
||||||
|
@ -88,6 +91,7 @@ namespace ChocolArm64
|
||||||
Set("1101101011000000000011xxxxxxxxxx", AInstEmit.Rev64, typeof(AOpCodeAlu));
|
Set("1101101011000000000011xxxxxxxxxx", AInstEmit.Rev64, typeof(AOpCodeAlu));
|
||||||
Set("x0011010110xxxxx001011xxxxxxxxxx", AInstEmit.Rorv, typeof(AOpCodeAluRs));
|
Set("x0011010110xxxxx001011xxxxxxxxxx", AInstEmit.Rorv, typeof(AOpCodeAluRs));
|
||||||
Set("x1011010000xxxxx000000xxxxxxxxxx", AInstEmit.Sbc, typeof(AOpCodeAluRs));
|
Set("x1011010000xxxxx000000xxxxxxxxxx", AInstEmit.Sbc, typeof(AOpCodeAluRs));
|
||||||
|
Set("x1111010000xxxxx000000xxxxxxxxxx", AInstEmit.Sbcs, typeof(AOpCodeAluRs));
|
||||||
Set("x00100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sbfm, typeof(AOpCodeBfm));
|
Set("x00100110xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Sbfm, typeof(AOpCodeBfm));
|
||||||
Set("x0011010110xxxxx000011xxxxxxxxxx", AInstEmit.Sdiv, typeof(AOpCodeAluRs));
|
Set("x0011010110xxxxx000011xxxxxxxxxx", AInstEmit.Sdiv, typeof(AOpCodeAluRs));
|
||||||
Set("10011011001xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Smaddl, typeof(AOpCodeMul));
|
Set("10011011001xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Smaddl, typeof(AOpCodeMul));
|
||||||
|
@ -138,57 +142,70 @@ namespace ChocolArm64
|
||||||
Set("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg));
|
Set("0>101110<<1xxxxx001111xxxxxxxxxx", AInstEmit.Cmhs_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd));
|
Set("0>101110<<100000100110xxxxxxxxxx", AInstEmit.Cmle_V, typeof(AOpCodeSimd));
|
||||||
Set("0>001110<<100000101010xxxxxxxxxx", AInstEmit.Cmlt_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("0x00111000100000010110xxxxxxxxxx", AInstEmit.Cnt_V, typeof(AOpCodeSimd));
|
||||||
Set("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns));
|
Set("0x001110000xxxxx000011xxxxxxxxxx", AInstEmit.Dup_Gp, typeof(AOpCodeSimdIns));
|
||||||
Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns));
|
Set("01011110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_S, typeof(AOpCodeSimdIns));
|
||||||
Set("0x001110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_V, typeof(AOpCodeSimdIns));
|
Set("0x001110000xxxxx000001xxxxxxxxxx", AInstEmit.Dup_V, typeof(AOpCodeSimdIns));
|
||||||
Set("0x101110001xxxxx000111xxxxxxxxxx", AInstEmit.Eor_V, typeof(AOpCodeSimdReg));
|
Set("0x101110001xxxxx000111xxxxxxxxxx", AInstEmit.Eor_V, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd));
|
Set("0>101110000xxxxx0<xxx0xxxxxxxxxx", AInstEmit.Ext_V, typeof(AOpCodeSimdExt));
|
||||||
Set("00011110xx1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg));
|
Set("011111101x1xxxxx110101xxxxxxxxxx", AInstEmit.Fabd_S, typeof(AOpCodeSimdReg));
|
||||||
Set("0x0011100x1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg));
|
Set("000111100x100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd));
|
||||||
Set("00011110xx1xxxxxxxxx01xxxxx0xxxx", AInstEmit.Fccmp_S, typeof(AOpCodeSimdFcond));
|
Set("000111100x1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx001000xxxxx0x000", AInstEmit.Fcmp_S, typeof(AOpCodeSimdReg));
|
Set("0>0011100<1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg));
|
Set("000111100x1xxxxxxxxx01xxxxx0xxxx", AInstEmit.Fccmp_S, typeof(AOpCodeSimdFcond));
|
||||||
Set("00011110xx1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond));
|
Set("000111100x1xxxxxxxxx01xxxxx1xxxx", AInstEmit.Fccmpe_S, typeof(AOpCodeSimdFcond));
|
||||||
Set("00011110xx10001xx10000xxxxxxxxxx", AInstEmit.Fcvt_S, typeof(AOpCodeSimd));
|
Set("000111100x1xxxxx001000xxxxx0x000", AInstEmit.Fcmp_S, typeof(AOpCodeSimdReg));
|
||||||
Set("x0011110xx100100000000xxxxxxxxxx", AInstEmit.Fcvtas_Gp, typeof(AOpCodeSimdCvt));
|
Set("000111100x1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg));
|
||||||
Set("x0011110xx100101000000xxxxxxxxxx", AInstEmit.Fcvtau_Gp, typeof(AOpCodeSimdCvt));
|
Set("000111100x1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond));
|
||||||
Set("x0011110xx110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt));
|
Set("000111100x10001xx10000xxxxxxxxxx", AInstEmit.Fcvt_S, typeof(AOpCodeSimd));
|
||||||
Set("x0011110xx101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt));
|
Set("x00111100x100100000000xxxxxxxxxx", AInstEmit.Fcvtas_Gp, typeof(AOpCodeSimdCvt));
|
||||||
Set("x0011110xx111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt));
|
Set("x00111100x100101000000xxxxxxxxxx", AInstEmit.Fcvtau_Gp, typeof(AOpCodeSimdCvt));
|
||||||
Set("x0011110xx011000xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzs_Gp_Fix, typeof(AOpCodeSimdCvt));
|
Set("0x0011100x100001011110xxxxxxxxxx", AInstEmit.Fcvtl_V, typeof(AOpCodeSimd));
|
||||||
Set("0x0011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzs_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("0x0011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzs_V, typeof(AOpCodeSimdShImm));
|
||||||
Set("x0011110xx111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_Gp, typeof(AOpCodeSimdCvt));
|
Set("x00111100x111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_Gp, typeof(AOpCodeSimdCvt));
|
||||||
Set("x0011110xx011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Gp_Fix, typeof(AOpCodeSimdCvt));
|
Set("x00111100x011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Gp_Fix, typeof(AOpCodeSimdCvt));
|
||||||
Set("0x1011101x100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimd));
|
Set("0>1011101<100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimd));
|
||||||
Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimdShImm));
|
Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimdShImm));
|
||||||
Set("00011110xx1xxxxx000110xxxxxxxxxx", AInstEmit.Fdiv_S, typeof(AOpCodeSimdReg));
|
Set("000111100x1xxxxx000110xxxxxxxxxx", AInstEmit.Fdiv_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011111xx0xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fmadd_S, typeof(AOpCodeSimdReg));
|
Set("0>1011100<1xxxxx111111xxxxxxxxxx", AInstEmit.Fdiv_V, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx010010xxxxxxxxxx", AInstEmit.Fmax_S, typeof(AOpCodeSimdReg));
|
Set("000111110x0xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fmadd_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx011010xxxxxxxxxx", AInstEmit.Fmaxnm_S, typeof(AOpCodeSimdReg));
|
Set("000111100x1xxxxx010010xxxxxxxxxx", AInstEmit.Fmax_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg));
|
Set("000111100x1xxxxx011010xxxxxxxxxx", AInstEmit.Fmaxnm_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg));
|
Set("000111100x1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg));
|
||||||
Set("0x0011100x1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg));
|
Set("000111100x1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg));
|
||||||
Set("0x0011111<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Ve, typeof(AOpCodeSimdRegElem));
|
Set("0>0011100<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx100000010000xxxxxxxxxx", AInstEmit.Fmov_S, typeof(AOpCodeSimd));
|
Set("0x0011111<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Ve, typeof(AOpCodeSimdRegElemF));
|
||||||
|
Set("000111100x100000010000xxxxxxxxxx", AInstEmit.Fmov_S, typeof(AOpCodeSimd));
|
||||||
Set("00011110xx1xxxxxxxx100xxxxxxxxxx", AInstEmit.Fmov_Si, typeof(AOpCodeSimdFmov));
|
Set("00011110xx1xxxxxxxx100xxxxxxxxxx", AInstEmit.Fmov_Si, typeof(AOpCodeSimdFmov));
|
||||||
Set("0xx0111100000xxx111101xxxxxxxxxx", AInstEmit.Fmov_V, typeof(AOpCodeSimdImm));
|
Set("0xx0111100000xxx111101xxxxxxxxxx", AInstEmit.Fmov_V, typeof(AOpCodeSimdImm));
|
||||||
Set("x0011110xx100110000000xxxxxxxxxx", AInstEmit.Fmov_Ftoi, typeof(AOpCodeSimdCvt));
|
Set("x00111100x100110000000xxxxxxxxxx", AInstEmit.Fmov_Ftoi, typeof(AOpCodeSimdCvt));
|
||||||
Set("x0011110xx100111000000xxxxxxxxxx", AInstEmit.Fmov_Itof, typeof(AOpCodeSimdCvt));
|
Set("x00111100x100111000000xxxxxxxxxx", AInstEmit.Fmov_Itof, typeof(AOpCodeSimdCvt));
|
||||||
Set("x0011110xx101110000000xxxxxxxxxx", AInstEmit.Fmov_Ftoi1, typeof(AOpCodeSimdCvt));
|
Set("1001111010101110000000xxxxxxxxxx", AInstEmit.Fmov_Ftoi1, typeof(AOpCodeSimdCvt));
|
||||||
Set("x0011110xx101111000000xxxxxxxxxx", AInstEmit.Fmov_Itof1, typeof(AOpCodeSimdCvt));
|
Set("1001111010101111000000xxxxxxxxxx", AInstEmit.Fmov_Itof1, typeof(AOpCodeSimdCvt));
|
||||||
Set("00011111xx0xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fmsub_S, typeof(AOpCodeSimdReg));
|
Set("000111110x0xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fmsub_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx000010xxxxxxxxxx", AInstEmit.Fmul_S, typeof(AOpCodeSimdReg));
|
Set("000111100x1xxxxx000010xxxxxxxxxx", AInstEmit.Fmul_S, typeof(AOpCodeSimdReg));
|
||||||
Set("0x1011100x1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg));
|
Set("0>1011100<1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x0011111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Ve, typeof(AOpCodeSimdRegElem));
|
Set("0x0011111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Ve, typeof(AOpCodeSimdRegElemF));
|
||||||
Set("00011110xx100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimdReg));
|
Set("000111100x100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx1xxxxx100010xxxxxxxxxx", AInstEmit.Fnmul_S, typeof(AOpCodeSimdReg));
|
Set("000111110x1xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fnmsub_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd));
|
Set("000111100x1xxxxx100010xxxxxxxxxx", AInstEmit.Fnmul_S, typeof(AOpCodeSimdReg));
|
||||||
Set("00011110xx100101010000xxxxxxxxxx", AInstEmit.Frintm_S, typeof(AOpCodeSimd));
|
Set("000111100x100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd));
|
||||||
Set("00011110xx100001110000xxxxxxxxxx", AInstEmit.Fsqrt_S, typeof(AOpCodeSimd));
|
Set("000111100x100101010000xxxxxxxxxx", AInstEmit.Frintm_S, typeof(AOpCodeSimd));
|
||||||
Set("00011110xx1xxxxx001110xxxxxxxxxx", AInstEmit.Fsub_S, typeof(AOpCodeSimdReg));
|
Set("0>0011100<100001100110xxxxxxxxxx", AInstEmit.Frintm_V, typeof(AOpCodeSimd));
|
||||||
Set("0x0011101x1xxxxx110101xxxxxxxxxx", AInstEmit.Fsub_V, typeof(AOpCodeSimdReg));
|
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("01001110000xxxxx000111xxxxxxxxxx", AInstEmit.Ins_Gp, typeof(AOpCodeSimdIns));
|
||||||
Set("01101110000xxxxx0xxxx1xxxxxxxxxx", AInstEmit.Ins_V, typeof(AOpCodeSimdIns));
|
Set("01101110000xxxxx0xxxx1xxxxxxxxxx", AInstEmit.Ins_V, typeof(AOpCodeSimdIns));
|
||||||
Set("0x00110001000000xxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms, typeof(AOpCodeSimdMemMs));
|
Set("0x00110001000000xxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms, typeof(AOpCodeSimdMemMs));
|
||||||
|
@ -209,6 +226,7 @@ namespace ChocolArm64
|
||||||
Set("0x00111100000xxx110x01xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));
|
Set("0x00111100000xxx110x01xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));
|
||||||
Set("0xx0111100000xxx111001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));
|
Set("0xx0111100000xxx111001xxxxxxxxxx", AInstEmit.Movi_V, typeof(AOpCodeSimdImm));
|
||||||
Set("0x001110<<1xxxxx100111xxxxxxxxxx", AInstEmit.Mul_V, typeof(AOpCodeSimdReg));
|
Set("0x001110<<1xxxxx100111xxxxxxxxxx", AInstEmit.Mul_V, typeof(AOpCodeSimdReg));
|
||||||
|
Set("0x001111xxxxxxxx1000x0xxxxxxxxxx", AInstEmit.Mul_Ve, typeof(AOpCodeSimdRegElem));
|
||||||
Set("0x10111100000xxx0xx001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm));
|
Set("0x10111100000xxx0xx001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm));
|
||||||
Set("0x10111100000xxx10x001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm));
|
Set("0x10111100000xxx10x001xxxxxxxxxx", AInstEmit.Mvni_V, typeof(AOpCodeSimdImm));
|
||||||
Set("0x10111100000xxx110x01xxxxxxxxxx", 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("0x10111000100000010110xxxxxxxxxx", AInstEmit.Not_V, typeof(AOpCodeSimd));
|
||||||
Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg));
|
Set("0x001110101xxxxx000111xxxxxxxxxx", AInstEmit.Orr_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x00111100000xxx<<x101xxxxxxxxxx", AInstEmit.Orr_Vi, typeof(AOpCodeSimdImm));
|
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("0x001110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Saddw_V, typeof(AOpCodeSimdReg));
|
||||||
Set("x0011110xx100010000000xxxxxxxxxx", AInstEmit.Scvtf_Gp, typeof(AOpCodeSimdCvt));
|
Set("x0011110xx100010000000xxxxxxxxxx", AInstEmit.Scvtf_Gp, typeof(AOpCodeSimdCvt));
|
||||||
Set("010111100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_S, typeof(AOpCodeSimd));
|
Set("010111100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_S, typeof(AOpCodeSimd));
|
||||||
Set("0x0011100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_V, typeof(AOpCodeSimd));
|
Set("0x0011100x100001110110xxxxxxxxxx", AInstEmit.Scvtf_V, typeof(AOpCodeSimd));
|
||||||
Set("010111110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_S, typeof(AOpCodeSimdShImm));
|
Set("010111110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_S, typeof(AOpCodeSimdShImm));
|
||||||
Set("0x0011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_V, 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("0x00111100>>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm));
|
||||||
Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg));
|
Set("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_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("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V, typeof(AOpCodeSimdShImm));
|
Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V, typeof(AOpCodeSimdShImm));
|
||||||
Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S, typeof(AOpCodeSimdShImm));
|
Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S, typeof(AOpCodeSimdShImm));
|
||||||
Set("0x0011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_V, 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("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
||||||
Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
||||||
Set("0x00110100000000xx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs));
|
Set("0x00110100000000xx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs));
|
||||||
|
@ -249,13 +272,17 @@ namespace ChocolArm64
|
||||||
Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd));
|
Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd));
|
||||||
Set("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd));
|
Set("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd));
|
||||||
Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
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("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm));
|
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>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm));
|
||||||
Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
||||||
Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));
|
Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x001110xx0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg));
|
Set("0x001110xx0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg));
|
||||||
Set("0x001110<<100001001010xxxxxxxxxx", AInstEmit.Xtn_V, typeof(AOpCodeSimd));
|
Set("0x001110<<100001001010xxxxxxxxxx", AInstEmit.Xtn_V, typeof(AOpCodeSimd));
|
||||||
|
Set("0x001110xx0xxxxx001110xxxxxxxxxx", AInstEmit.Zip1_V, typeof(AOpCodeSimdReg));
|
||||||
|
Set("0x001110xx0xxxxx011110xxxxxxxxxx", AInstEmit.Zip2_V, typeof(AOpCodeSimdReg));
|
||||||
#endregion
|
#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 AThreadState ThreadState { get; private set; }
|
||||||
public AMemory Memory { get; private set; }
|
public AMemory Memory { get; private set; }
|
||||||
|
|
||||||
public long EntryPoint { get; private set; }
|
private long EntryPoint;
|
||||||
|
|
||||||
private ATranslator Translator;
|
private ATranslator Translator;
|
||||||
|
|
||||||
private ThreadPriority Priority;
|
|
||||||
|
|
||||||
private Thread Work;
|
private Thread Work;
|
||||||
|
|
||||||
public event EventHandler WorkFinished;
|
public event EventHandler WorkFinished;
|
||||||
|
|
||||||
public int ThreadId => ThreadState.ThreadId;
|
public int ThreadId => ThreadState.ThreadId;
|
||||||
|
|
||||||
public bool IsAlive => Work.IsAlive;
|
private int IsExecuting;
|
||||||
|
|
||||||
private bool IsExecuting;
|
public AThread(ATranslator Translator, AMemory Memory, long EntryPoint)
|
||||||
|
|
||||||
private object ExecuteLock;
|
|
||||||
|
|
||||||
public AThread(AMemory Memory, ThreadPriority Priority, long EntryPoint)
|
|
||||||
{
|
{
|
||||||
|
this.Translator = Translator;
|
||||||
this.Memory = Memory;
|
this.Memory = Memory;
|
||||||
this.Priority = Priority;
|
|
||||||
this.EntryPoint = EntryPoint;
|
this.EntryPoint = EntryPoint;
|
||||||
|
|
||||||
ThreadState = new AThreadState();
|
ThreadState = new AThreadState();
|
||||||
Translator = new ATranslator(this);
|
|
||||||
ExecuteLock = new object();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StopExecution() => Translator.StopExecution();
|
ThreadState.Running = true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Execute()
|
public bool Execute()
|
||||||
{
|
{
|
||||||
lock (ExecuteLock)
|
if (Interlocked.Exchange(ref IsExecuting, 1) == 1)
|
||||||
{
|
|
||||||
if (IsExecuting)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
IsExecuting = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Work = new Thread(delegate()
|
Work = new Thread(delegate()
|
||||||
{
|
{
|
||||||
Translator.ExecuteSubroutine(EntryPoint);
|
Translator.ExecuteSubroutine(this, EntryPoint);
|
||||||
|
|
||||||
Memory.RemoveMonitor(ThreadId);
|
Memory.RemoveMonitor(ThreadId);
|
||||||
|
|
||||||
WorkFinished?.Invoke(this, EventArgs.Empty);
|
WorkFinished?.Invoke(this, EventArgs.Empty);
|
||||||
});
|
});
|
||||||
|
|
||||||
Work.Priority = Priority;
|
|
||||||
|
|
||||||
Work.Start();
|
Work.Start();
|
||||||
|
|
||||||
return true;
|
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.Instruction;
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
|
@ -8,7 +9,31 @@ namespace ChocolArm64.Decoder
|
||||||
{
|
{
|
||||||
static class ADecoder
|
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> Visited = new Dictionary<long, ABlock>();
|
||||||
Dictionary<long, ABlock> VisitedEnd = new Dictionary<long, ABlock>();
|
Dictionary<long, ABlock> VisitedEnd = new Dictionary<long, ABlock>();
|
||||||
|
@ -35,7 +60,7 @@ namespace ChocolArm64.Decoder
|
||||||
{
|
{
|
||||||
ABlock Current = Blocks.Dequeue();
|
ABlock Current = Blocks.Dequeue();
|
||||||
|
|
||||||
FillBlock(Translator.Thread.Memory, Current);
|
FillBlock(Memory, Current);
|
||||||
|
|
||||||
//Set child blocks. "Branch" is the block the branch instruction
|
//Set child blocks. "Branch" is the block the branch instruction
|
||||||
//points to (when taken), "Next" is the block at the next address,
|
//points to (when taken), "Next" is the block at the next address,
|
||||||
|
@ -59,8 +84,8 @@ namespace ChocolArm64.Decoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!(LastOp is AOpCodeBImmAl) &&
|
if (!((LastOp is AOpCodeBImmAl) ||
|
||||||
!(LastOp is AOpCodeBReg)) || HasCachedSub)
|
(LastOp is AOpCodeBReg)) || HasCachedSub)
|
||||||
{
|
{
|
||||||
Current.Next = Enqueue(Current.EndPosition);
|
Current.Next = Enqueue(Current.EndPosition);
|
||||||
}
|
}
|
||||||
|
@ -165,28 +190,29 @@ namespace ChocolArm64.Decoder
|
||||||
|
|
||||||
if (Inst.Type != null)
|
if (Inst.Type != null)
|
||||||
{
|
{
|
||||||
DecodedOpCode = CreateOpCode(Inst.Type, Inst, Position, OpCode);
|
DecodedOpCode = MakeOpCode(Inst.Type, Inst, Position, OpCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DecodedOpCode;
|
return DecodedOpCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate object OpActivator(AInst Inst, long Position, int OpCode);
|
private static AOpCode MakeOpCode(Type Type, 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)
|
|
||||||
{
|
{
|
||||||
if (Type == null)
|
if (Type == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(Type));
|
throw new ArgumentNullException(nameof(Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Activators.TryGetValue(Type, out OpActivator 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) };
|
Type[] ArgTypes = new Type[] { typeof(AInst), typeof(long), typeof(int) };
|
||||||
|
|
||||||
DynamicMethod Mthd = new DynamicMethod($"{Type.Name}_Create", Type, ArgTypes);
|
DynamicMethod Mthd = new DynamicMethod($"Make{Type.Name}", Type, ArgTypes);
|
||||||
|
|
||||||
ILGenerator Generator = Mthd.GetILGenerator();
|
ILGenerator Generator = Mthd.GetILGenerator();
|
||||||
|
|
||||||
|
@ -196,12 +222,7 @@ namespace ChocolArm64.Decoder
|
||||||
Generator.Emit(OpCodes.Newobj, Type.GetConstructor(ArgTypes));
|
Generator.Emit(OpCodes.Newobj, Type.GetConstructor(ArgTypes));
|
||||||
Generator.Emit(OpCodes.Ret);
|
Generator.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
CreateInstance = (OpActivator)Mthd.CreateDelegate(typeof(OpActivator));
|
return (OpActivator)Mthd.CreateDelegate(typeof(OpActivator));
|
||||||
|
|
||||||
Activators.Add(Type, CreateInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (AOpCode)CreateInstance(Inst, Position, OpCode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,8 +10,6 @@ namespace ChocolArm64.Decoder
|
||||||
public int Opc { get; private set; }
|
public int Opc { get; private set; }
|
||||||
public int Size { get; protected set; }
|
public int Size { get; protected set; }
|
||||||
|
|
||||||
public int SizeF => Size & 1;
|
|
||||||
|
|
||||||
public AOpCodeSimd(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
public AOpCodeSimd(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||||
{
|
{
|
||||||
Rd = (OpCode >> 0) & 0x1f;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ namespace ChocolArm64.Decoder
|
||||||
{
|
{
|
||||||
public bool Bit3 { get; private set; }
|
public bool Bit3 { get; private set; }
|
||||||
public int Ra { get; private set; }
|
public int Ra { get; private set; }
|
||||||
public int Rm { get; private set; }
|
public int Rm { get; protected set; }
|
||||||
|
|
||||||
public AOpCodeSimdReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
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
|
namespace ChocolArm64.Decoder
|
||||||
{
|
{
|
||||||
class AOpCodeSimdRegElem : AOpCodeSimdReg
|
class AOpCodeSimdRegElemF : AOpCodeSimdReg
|
||||||
{
|
{
|
||||||
public int Index { get; private set; }
|
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)
|
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;
|
using System;
|
||||||
|
|
||||||
namespace ChocolArm64.State
|
namespace ChocolArm64.Events
|
||||||
{
|
{
|
||||||
public class AInstUndEventArgs : EventArgs
|
public class AInstUndefinedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public long Position { get; private set; }
|
public long Position { get; private set; }
|
||||||
public int RawOpCode { 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.Position = Position;
|
||||||
this.RawOpCode = RawOpCode;
|
this.RawOpCode = RawOpCode;
|
|
@ -11,7 +11,10 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
static partial class AInstEmit
|
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);
|
EmitDataLoadOpers(Context);
|
||||||
|
|
||||||
|
@ -27,11 +30,19 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
if (Context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
if (Context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||||
{
|
{
|
||||||
Context.Emit(OpCodes.Conv_I8);
|
Context.Emit(OpCodes.Conv_U8);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.Emit(OpCodes.Add);
|
Context.Emit(OpCodes.Add);
|
||||||
|
|
||||||
|
if (SetFlags)
|
||||||
|
{
|
||||||
|
Context.EmitZNFlagCheck();
|
||||||
|
|
||||||
|
EmitAdcsCCheck(Context);
|
||||||
|
EmitAddsVCheck(Context);
|
||||||
|
}
|
||||||
|
|
||||||
EmitDataStore(Context);
|
EmitDataStore(Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +118,16 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitStintzr(Op.Rd);
|
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 Eor(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Xor);
|
||||||
|
|
||||||
public static void Extr(AILEmitterCtx Context)
|
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 Lslv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shl);
|
||||||
public static void Lsrv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shr_Un);
|
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);
|
EmitDataLoadOpers(Context);
|
||||||
|
|
||||||
|
@ -155,11 +179,19 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
if (Context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
if (Context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||||
{
|
{
|
||||||
Context.Emit(OpCodes.Conv_I8);
|
Context.Emit(OpCodes.Conv_U8);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.Emit(OpCodes.Sub);
|
Context.Emit(OpCodes.Sub);
|
||||||
|
|
||||||
|
if (SetFlags)
|
||||||
|
{
|
||||||
|
Context.EmitZNFlagCheck();
|
||||||
|
|
||||||
|
EmitSbcsCCheck(Context);
|
||||||
|
EmitSubsVCheck(Context);
|
||||||
|
}
|
||||||
|
|
||||||
EmitDataStore(Context);
|
EmitDataStore(Context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,31 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
static class AInstEmitAluHelper
|
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)
|
public static void EmitAddsCCheck(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
//C = Rd < Rn
|
//C = Rd < Rn
|
||||||
|
@ -41,6 +66,25 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitStflg((int)APState.VBit);
|
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)
|
public static void EmitSubsCCheck(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
//C = Rn == Rm || Rn > Rm = !(Rn < Rm)
|
//C = Rn == Rm || Rn > Rm = !(Rn < Rm)
|
||||||
|
@ -145,5 +189,24 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitStint(Op.Rd);
|
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)
|
if (Op.Pos + 1 == BitsCount)
|
||||||
{
|
{
|
||||||
EmitBfmShift(Context, OpCodes.Shr);
|
EmitSbfmShift(Context);
|
||||||
}
|
}
|
||||||
else if (Op.Pos < Op.Shift)
|
else if (Op.Pos < Op.Shift)
|
||||||
{
|
{
|
||||||
|
@ -54,15 +54,6 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
EmitSbfmCast(Context, OpCodes.Conv_I4);
|
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
|
else
|
||||||
{
|
{
|
||||||
EmitBfmLoadRn(Context);
|
EmitBfmLoadRn(Context);
|
||||||
|
@ -87,7 +78,7 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
if (Op.Pos + 1 == Op.GetBitsCount())
|
if (Op.Pos + 1 == Op.GetBitsCount())
|
||||||
{
|
{
|
||||||
EmitBfmShift(Context, OpCodes.Shr_Un);
|
EmitUbfmShift(Context);
|
||||||
}
|
}
|
||||||
else if (Op.Pos < Op.Shift)
|
else if (Op.Pos < Op.Shift)
|
||||||
{
|
{
|
||||||
|
@ -166,20 +157,29 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitStintzr(Op.Rd);
|
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;
|
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||||
|
|
||||||
if (Op.Shift > 0)
|
|
||||||
{
|
|
||||||
Context.EmitLdintzr(Op.Rn);
|
Context.EmitLdintzr(Op.Rn);
|
||||||
Context.EmitLdc_I4(Op.Shift);
|
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)
|
private static void EmitBfmLsl(AILEmitterCtx Context)
|
||||||
{
|
{
|
|
@ -44,16 +44,15 @@ namespace ChocolArm64.Instruction
|
||||||
Context.Emit(OpCodes.Neg);
|
Context.Emit(OpCodes.Neg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.EmitStintzr(Op.Rd);
|
|
||||||
|
|
||||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||||
|
|
||||||
Context.MarkLabel(LblTrue);
|
Context.MarkLabel(LblTrue);
|
||||||
|
|
||||||
Context.EmitLdintzr(Op.Rn);
|
Context.EmitLdintzr(Op.Rn);
|
||||||
Context.EmitStintzr(Op.Rd);
|
|
||||||
|
|
||||||
Context.MarkLabel(LblEnd);
|
Context.MarkLabel(LblEnd);
|
||||||
|
|
||||||
|
Context.EmitStintzr(Op.Rd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@ using ChocolArm64.Decoder;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
namespace ChocolArm64.Instruction
|
namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
|
@ -33,10 +34,32 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
Context.EmitCall(MthdInfo);
|
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)
|
if (Context.CurrBlock.Next != null)
|
||||||
{
|
{
|
||||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Context.EmitLdc_I8(Op.Position + 4);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Und(AILEmitterCtx Context)
|
public static void Und(AILEmitterCtx Context)
|
||||||
|
@ -60,6 +83,12 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
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;
|
AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;
|
||||||
|
|
||||||
|
if (Context.CurrBlock.Branch != null)
|
||||||
|
{
|
||||||
Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm));
|
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)
|
public static void B_Cond(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeBImmCond Op = (AOpCodeBImmCond)Context.CurrOp;
|
AOpCodeBImmCond Op = (AOpCodeBImmCond)Context.CurrOp;
|
||||||
|
|
||||||
Context.EmitCondBranch(Context.GetLabel(Op.Imm), Op.Cond);
|
EmitBranch(Context, Op.Cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Bl(AILEmitterCtx Context)
|
public static void Bl(AILEmitterCtx Context)
|
||||||
|
@ -48,11 +58,8 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
Context.Emit(OpCodes.Pop);
|
Context.Emit(OpCodes.Pop);
|
||||||
|
|
||||||
if (Context.CurrBlock.Next != null)
|
|
||||||
{
|
|
||||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Context.EmitLdc_I8(Op.Imm);
|
Context.EmitLdc_I8(Op.Imm);
|
||||||
|
@ -93,7 +100,7 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitLdintzr(Op.Rt);
|
Context.EmitLdintzr(Op.Rt);
|
||||||
Context.EmitLdc_I(0);
|
Context.EmitLdc_I(0);
|
||||||
|
|
||||||
Context.Emit(ILOp, Context.GetLabel(Op.Imm));
|
EmitBranch(Context, ILOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ret(AILEmitterCtx Context)
|
public static void Ret(AILEmitterCtx Context)
|
||||||
|
@ -118,7 +125,65 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
Context.EmitLdc_I(0);
|
Context.EmitLdc_I(0);
|
||||||
|
|
||||||
|
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));
|
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)
|
public static void Fabs_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitScalarUnaryOpF(Context, () =>
|
EmitScalarUnaryOpF(Context, () =>
|
||||||
|
@ -124,6 +134,11 @@ namespace ChocolArm64.Instruction
|
||||||
EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
|
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)
|
public static void Fmadd_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitScalarTernaryRaOpF(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)
|
public static void Frinta_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
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)
|
public static void Fsqrt_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitScalarUnaryOpF(Context, () =>
|
EmitScalarUnaryOpF(Context, () =>
|
||||||
|
@ -275,6 +349,11 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
|
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)
|
public static void Neg_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
|
EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
|
||||||
|
@ -282,7 +361,7 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
public static void Saddw_V(AILEmitterCtx Context)
|
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)
|
public static void Smax_V(AILEmitterCtx Context)
|
||||||
|
@ -303,6 +382,20 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
|
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)
|
public static void Sub_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
|
EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
|
||||||
|
@ -333,7 +426,12 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
public static void Uaddw_V(AILEmitterCtx Context)
|
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;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
|
using static ChocolArm64.Instruction.AInstEmitAluHelper;
|
||||||
using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
||||||
|
|
||||||
namespace ChocolArm64.Instruction
|
namespace ChocolArm64.Instruction
|
||||||
|
@ -45,6 +46,45 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorCmp(Context, OpCodes.Blt_S);
|
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)
|
public static void Fccmp_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
||||||
|
@ -54,24 +94,9 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
Context.EmitCondBranch(LblTrue, Op.Cond);
|
Context.EmitCondBranch(LblTrue, Op.Cond);
|
||||||
|
|
||||||
//TODO: Share this logic with Ccmp.
|
EmitSetNZCV(Context, Op.NZCV);
|
||||||
Context.EmitLdc_I4((Op.NZCV >> 0) & 1);
|
|
||||||
|
|
||||||
Context.EmitStflg((int)APState.VBit);
|
Context.Emit(OpCodes.Br, LblEnd);
|
||||||
|
|
||||||
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.MarkLabel(LblTrue);
|
Context.MarkLabel(LblTrue);
|
||||||
|
|
||||||
|
@ -80,12 +105,35 @@ namespace ChocolArm64.Instruction
|
||||||
Context.MarkLabel(LblEnd);
|
Context.MarkLabel(LblEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Fccmpe_S(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
Fccmp_S(Context);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fcmp_S(AILEmitterCtx Context)
|
public static void Fcmp_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||||
|
|
||||||
bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false;
|
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()
|
void EmitLoadOpers()
|
||||||
{
|
{
|
||||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||||
|
@ -123,30 +171,18 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
Context.EmitStflg((int)APState.NBit);
|
Context.EmitStflg((int)APState.NBit);
|
||||||
|
|
||||||
//Handle NaN case. If any number is NaN, then NZCV = 0011.
|
//V = 0
|
||||||
AILLabel LblNotNaN = new AILLabel();
|
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.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)
|
public static void Fcmpe_S(AILEmitterCtx Context)
|
|
@ -23,52 +23,127 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
public static void Fcvtas_Gp(AILEmitterCtx Context)
|
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)
|
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)
|
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)
|
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)
|
public static void Fcvtzs_Gp(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitFcvtz__Gp(Context, Signed: true);
|
EmitFcvt_s_Gp(Context, () => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fcvtzs_Gp_Fix(AILEmitterCtx 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)
|
public static void Fcvtzs_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitVectorFcvt(Context, Signed: true);
|
EmitVectorFcvtzs(Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fcvtzu_Gp(AILEmitterCtx 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)
|
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)
|
public static void Fcvtzu_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitVectorFcvt(Context, Signed: false);
|
EmitVectorFcvtzu(Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Scvtf_Gp(AILEmitterCtx Context)
|
public static void Scvtf_Gp(AILEmitterCtx Context)
|
||||||
|
@ -91,7 +166,7 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
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);
|
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;
|
AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
|
||||||
|
|
||||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||||
|
|
||||||
EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
|
Emit();
|
||||||
|
|
||||||
if (Signed)
|
if (Signed)
|
||||||
{
|
{
|
||||||
|
@ -190,45 +275,14 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitStintzr(Op.Rd);
|
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;
|
EmitFcvtz__Gp_Fix(Context, true);
|
||||||
|
|
||||||
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);
|
private static void EmitFcvtzu_Gp_Fix(AILEmitterCtx Context)
|
||||||
}
|
|
||||||
|
|
||||||
private static void EmitFcvtz__Gp(AILEmitterCtx Context, bool Signed)
|
|
||||||
{
|
{
|
||||||
AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
|
EmitFcvtz__Gp_Fix(Context, false);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitFcvtz__Gp_Fix(AILEmitterCtx Context, bool Signed)
|
private static void EmitFcvtz__Gp_Fix(AILEmitterCtx Context, bool Signed)
|
||||||
|
@ -254,6 +308,16 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitStintzr(Op.Rd);
|
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)
|
private static void EmitVectorCvtf(AILEmitterCtx Context, bool Signed)
|
||||||
{
|
{
|
||||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
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;
|
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||||
|
|
|
@ -36,20 +36,18 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
int SizeF = Op.Size & 1;
|
||||||
|
|
||||||
MethodInfo MthdInfo;
|
MethodInfo MthdInfo;
|
||||||
|
|
||||||
if (Op.Size == 0)
|
if (SizeF == 0)
|
||||||
{
|
{
|
||||||
MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float) });
|
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) });
|
MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double) });
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Context.EmitCall(MthdInfo);
|
Context.EmitCall(MthdInfo);
|
||||||
}
|
}
|
||||||
|
@ -58,20 +56,18 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
int SizeF = Op.Size & 1;
|
||||||
|
|
||||||
MethodInfo MthdInfo;
|
MethodInfo MthdInfo;
|
||||||
|
|
||||||
if (Op.Size == 0)
|
if (SizeF == 0)
|
||||||
{
|
{
|
||||||
MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float), typeof(float) });
|
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) });
|
MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double), typeof(double) });
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Context.EmitCall(MthdInfo);
|
Context.EmitCall(MthdInfo);
|
||||||
}
|
}
|
||||||
|
@ -80,28 +76,26 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
int SizeF = Op.Size & 1;
|
||||||
|
|
||||||
Context.EmitLdc_I4((int)RoundMode);
|
Context.EmitLdc_I4((int)RoundMode);
|
||||||
|
|
||||||
MethodInfo MthdInfo;
|
MethodInfo MthdInfo;
|
||||||
|
|
||||||
Type[] Types = new Type[] { null, typeof(MidpointRounding) };
|
Type[] Types = new Type[] { null, typeof(MidpointRounding) };
|
||||||
|
|
||||||
Types[0] = Op.Size == 0
|
Types[0] = SizeF == 0
|
||||||
? typeof(float)
|
? typeof(float)
|
||||||
: typeof(double);
|
: typeof(double);
|
||||||
|
|
||||||
if (Op.Size == 0)
|
if (SizeF == 0)
|
||||||
{
|
{
|
||||||
MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types);
|
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);
|
MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Context.EmitCall(MthdInfo);
|
Context.EmitCall(MthdInfo);
|
||||||
}
|
}
|
||||||
|
@ -133,7 +127,7 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
public static void EmitScalarOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed)
|
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))
|
if (Opers.HasFlag(OperFlags.Rd))
|
||||||
{
|
{
|
||||||
|
@ -147,7 +141,7 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
if (Opers.HasFlag(OperFlags.Rm))
|
if (Opers.HasFlag(OperFlags.Rm))
|
||||||
{
|
{
|
||||||
EmitVectorExtract(Context, Op.Rm, 0, Op.Size, Signed);
|
EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, 0, Op.Size, Signed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Emit();
|
Emit();
|
||||||
|
@ -196,6 +190,11 @@ namespace ChocolArm64.Instruction
|
||||||
EmitScalarSetF(Context, Op.Rd, SizeF);
|
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)
|
public static void EmitVectorBinaryOpF(AILEmitterCtx Context, Action Emit)
|
||||||
{
|
{
|
||||||
EmitVectorOpF(Context, Emit, OperFlags.RnRm);
|
EmitVectorOpF(Context, Emit, OperFlags.RnRm);
|
||||||
|
@ -206,23 +205,9 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorOpF(Context, Emit, OperFlags.RdRnRm);
|
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)
|
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;
|
int SizeF = Op.Size & 1;
|
||||||
|
|
||||||
|
@ -242,7 +227,7 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
if (Opers.HasFlag(OperFlags.Rm))
|
if (Opers.HasFlag(OperFlags.Rm))
|
||||||
{
|
{
|
||||||
EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
|
EmitVectorExtractF(Context, ((AOpCodeSimdReg)Op).Rm, Index, SizeF);
|
||||||
}
|
}
|
||||||
|
|
||||||
Emit();
|
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)
|
public static void EmitVectorOpByElemF(AILEmitterCtx Context, Action Emit, int Elem, bool Ternary)
|
||||||
{
|
{
|
||||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
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)
|
public static void EmitVectorImmUnaryOp(AILEmitterCtx Context, Action Emit)
|
||||||
{
|
{
|
||||||
EmitVectorImmOp(Context, Emit, false);
|
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;
|
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||||
|
|
||||||
|
@ -415,6 +462,53 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitStvec(Op.Rd);
|
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)
|
public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size)
|
||||||
{
|
{
|
||||||
EmitVectorZeroAll(Context, Reg);
|
EmitVectorZeroAll(Context, Reg);
|
|
@ -1,3 +1,5 @@
|
||||||
|
using ChocolArm64.Decoder;
|
||||||
|
using ChocolArm64.State;
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
|
@ -65,5 +67,28 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or));
|
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)
|
public static void Fcsel_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
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)
|
private static void EmitIntZeroHigherIfNeeded(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||||
|
@ -295,5 +333,29 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorZeroUpper(Context, Op.Rd);
|
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
|
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)
|
public static void Shl_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||||
|
@ -38,7 +29,16 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
int Shift = Op.Imm - (8 << Op.Size);
|
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)
|
public static void Shrn_V(AILEmitterCtx Context)
|
||||||
|
@ -83,7 +83,22 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
int Shift = (8 << (Op.Size + 1)) - Op.Imm;
|
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)
|
public static void Ushl_V(AILEmitterCtx Context)
|
||||||
|
@ -100,14 +115,43 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
|
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)
|
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)
|
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)
|
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;
|
EmitVectorShImmBinaryOp(Context, Emit, Imm, false, true);
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||||
|
|
||||||
for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
|
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.Rn, Index, Op.Size, Signed);
|
||||||
|
|
||||||
Context.EmitLdc_I4(Imm);
|
Context.EmitLdc_I4(Imm);
|
||||||
|
@ -247,7 +272,7 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
|
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;
|
int Elems = 8 >> Op.Size;
|
||||||
|
|
||||||
|
@ -282,7 +307,7 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
|
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;
|
int Elems = 8 >> Op.Size;
|
||||||
|
|
|
@ -9,6 +9,11 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
static partial class AInstEmit
|
static partial class AInstEmit
|
||||||
{
|
{
|
||||||
|
public static void Hint(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
//Execute as no-op.
|
||||||
|
}
|
||||||
|
|
||||||
public static void Mrs(AILEmitterCtx Context)
|
public static void Mrs(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
|
AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
|
|
@ -1,6 +1,7 @@
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace ChocolArm64.Instruction
|
namespace ChocolArm64.Instruction
|
||||||
|
@ -101,6 +102,8 @@ namespace ChocolArm64.Instruction
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int SatF32ToS32(float Value)
|
public static int SatF32ToS32(float Value)
|
||||||
{
|
{
|
||||||
|
if (float.IsNaN(Value)) return 0;
|
||||||
|
|
||||||
return Value > int.MaxValue ? int.MaxValue :
|
return Value > int.MaxValue ? int.MaxValue :
|
||||||
Value < int.MinValue ? int.MinValue : (int)Value;
|
Value < int.MinValue ? int.MinValue : (int)Value;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +111,8 @@ namespace ChocolArm64.Instruction
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static long SatF32ToS64(float Value)
|
public static long SatF32ToS64(float Value)
|
||||||
{
|
{
|
||||||
|
if (float.IsNaN(Value)) return 0;
|
||||||
|
|
||||||
return Value > long.MaxValue ? long.MaxValue :
|
return Value > long.MaxValue ? long.MaxValue :
|
||||||
Value < long.MinValue ? long.MinValue : (long)Value;
|
Value < long.MinValue ? long.MinValue : (long)Value;
|
||||||
}
|
}
|
||||||
|
@ -115,6 +120,8 @@ namespace ChocolArm64.Instruction
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static uint SatF32ToU32(float Value)
|
public static uint SatF32ToU32(float Value)
|
||||||
{
|
{
|
||||||
|
if (float.IsNaN(Value)) return 0;
|
||||||
|
|
||||||
return Value > uint.MaxValue ? uint.MaxValue :
|
return Value > uint.MaxValue ? uint.MaxValue :
|
||||||
Value < uint.MinValue ? uint.MinValue : (uint)Value;
|
Value < uint.MinValue ? uint.MinValue : (uint)Value;
|
||||||
}
|
}
|
||||||
|
@ -122,6 +129,8 @@ namespace ChocolArm64.Instruction
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong SatF32ToU64(float Value)
|
public static ulong SatF32ToU64(float Value)
|
||||||
{
|
{
|
||||||
|
if (float.IsNaN(Value)) return 0;
|
||||||
|
|
||||||
return Value > ulong.MaxValue ? ulong.MaxValue :
|
return Value > ulong.MaxValue ? ulong.MaxValue :
|
||||||
Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
|
Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +138,8 @@ namespace ChocolArm64.Instruction
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int SatF64ToS32(double Value)
|
public static int SatF64ToS32(double Value)
|
||||||
{
|
{
|
||||||
|
if (double.IsNaN(Value)) return 0;
|
||||||
|
|
||||||
return Value > int.MaxValue ? int.MaxValue :
|
return Value > int.MaxValue ? int.MaxValue :
|
||||||
Value < int.MinValue ? int.MinValue : (int)Value;
|
Value < int.MinValue ? int.MinValue : (int)Value;
|
||||||
}
|
}
|
||||||
|
@ -136,6 +147,8 @@ namespace ChocolArm64.Instruction
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static long SatF64ToS64(double Value)
|
public static long SatF64ToS64(double Value)
|
||||||
{
|
{
|
||||||
|
if (double.IsNaN(Value)) return 0;
|
||||||
|
|
||||||
return Value > long.MaxValue ? long.MaxValue :
|
return Value > long.MaxValue ? long.MaxValue :
|
||||||
Value < long.MinValue ? long.MinValue : (long)Value;
|
Value < long.MinValue ? long.MinValue : (long)Value;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +156,8 @@ namespace ChocolArm64.Instruction
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static uint SatF64ToU32(double Value)
|
public static uint SatF64ToU32(double Value)
|
||||||
{
|
{
|
||||||
|
if (double.IsNaN(Value)) return 0;
|
||||||
|
|
||||||
return Value > uint.MaxValue ? uint.MaxValue :
|
return Value > uint.MaxValue ? uint.MaxValue :
|
||||||
Value < uint.MinValue ? uint.MinValue : (uint)Value;
|
Value < uint.MinValue ? uint.MinValue : (uint)Value;
|
||||||
}
|
}
|
||||||
|
@ -150,46 +165,20 @@ namespace ChocolArm64.Instruction
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ulong SatF64ToU64(double Value)
|
public static ulong SatF64ToU64(double Value)
|
||||||
{
|
{
|
||||||
|
if (double.IsNaN(Value)) return 0;
|
||||||
|
|
||||||
return Value > ulong.MaxValue ? ulong.MaxValue :
|
return Value > ulong.MaxValue ? ulong.MaxValue :
|
||||||
Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
|
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);
|
return (long)(BigInteger.Multiply(LHS, RHS) >> 64);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ulong UMulHi128(ulong LHS, ulong RHS)
|
public static ulong UMulHi128(ulong LHS, ulong RHS)
|
||||||
{
|
{
|
||||||
ulong LLo = (uint)(LHS >> 0);
|
return (ulong)(BigInteger.Multiply(LHS, RHS) >> 64);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int CountSetBits8(byte Value)
|
public static int CountSetBits8(byte Value)
|
||||||
|
@ -200,6 +189,32 @@ namespace ChocolArm64.Instruction
|
||||||
(Value >> 6) & 1 + (Value >> 7);
|
(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)
|
public static AVec Tbl1_V64(AVec Vector, AVec Tb0)
|
||||||
{
|
{
|
||||||
return Tbl(Vector, 8, Tb0);
|
return Tbl(Vector, 8, Tb0);
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Exceptions;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace ChocolArm64.Memory
|
namespace ChocolArm64.Memory
|
||||||
{
|
{
|
||||||
public unsafe class AMemory
|
public unsafe class AMemory : IDisposable
|
||||||
{
|
{
|
||||||
private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1;
|
private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1;
|
||||||
|
|
||||||
|
@ -39,16 +39,20 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
private HashSet<long> ExAddrs;
|
private HashSet<long> ExAddrs;
|
||||||
|
|
||||||
|
public IntPtr Ram { get; private set; }
|
||||||
|
|
||||||
private byte* RamPtr;
|
private byte* RamPtr;
|
||||||
|
|
||||||
public AMemory(IntPtr Ram, AMemoryAlloc Allocator)
|
public AMemory()
|
||||||
{
|
{
|
||||||
Manager = new AMemoryMgr(Allocator);
|
Manager = new AMemoryMgr();
|
||||||
|
|
||||||
Monitors = new Dictionary<int, ExMonitor>();
|
Monitors = new Dictionary<int, ExMonitor>();
|
||||||
|
|
||||||
ExAddrs = new HashSet<long>();
|
ExAddrs = new HashSet<long>();
|
||||||
|
|
||||||
|
Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize + AMemoryMgr.PageSize);
|
||||||
|
|
||||||
RamPtr = (byte*)Ram;
|
RamPtr = (byte*)Ram;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,98 +138,79 @@ namespace ChocolArm64.Memory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sbyte ReadSByte(long Position) => (sbyte)ReadByte (Position);
|
public sbyte ReadSByte(long Position)
|
||||||
public short ReadInt16(long Position) => (short)ReadUInt16(Position);
|
{
|
||||||
public int ReadInt32(long Position) => (int)ReadUInt32(Position);
|
return (sbyte)ReadByte(Position);
|
||||||
public long ReadInt64(long Position) => (long)ReadUInt64(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)
|
public byte ReadByte(long Position)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
||||||
#endif
|
|
||||||
|
|
||||||
return *((byte*)(RamPtr + (uint)Position));
|
return ReadByteUnchecked(Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ushort ReadUInt16(long Position)
|
public ushort ReadUInt16(long Position)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
EnsureAccessIsValid(Position + 0, AMemoryPerm.Read);
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
EnsureAccessIsValid(Position + 1, AMemoryPerm.Read);
|
||||||
#endif
|
|
||||||
|
|
||||||
return *((ushort*)(RamPtr + (uint)Position));
|
return ReadUInt16Unchecked(Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public uint ReadUInt32(long Position)
|
public uint ReadUInt32(long Position)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
EnsureAccessIsValid(Position + 0, AMemoryPerm.Read);
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
EnsureAccessIsValid(Position + 3, AMemoryPerm.Read);
|
||||||
#endif
|
|
||||||
|
|
||||||
return *((uint*)(RamPtr + (uint)Position));
|
return ReadUInt32Unchecked(Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ulong ReadUInt64(long Position)
|
public ulong ReadUInt64(long Position)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
EnsureAccessIsValid(Position + 0, AMemoryPerm.Read);
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
EnsureAccessIsValid(Position + 7, AMemoryPerm.Read);
|
||||||
#endif
|
|
||||||
|
|
||||||
return *((ulong*)(RamPtr + (uint)Position));
|
return ReadUInt64Unchecked(Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public AVec ReadVector8(long Position)
|
public AVec ReadVector8(long Position)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return new AVec() { B0 = ReadByte(Position) };
|
return new AVec() { B0 = ReadByte(Position) };
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public AVec ReadVector16(long Position)
|
public AVec ReadVector16(long Position)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return new AVec() { H0 = ReadUInt16(Position) };
|
return new AVec() { H0 = ReadUInt16(Position) };
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public AVec ReadVector32(long Position)
|
public AVec ReadVector32(long Position)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return new AVec() { W0 = ReadUInt32(Position) };
|
return new AVec() { W0 = ReadUInt32(Position) };
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public AVec ReadVector64(long Position)
|
public AVec ReadVector64(long Position)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return new AVec() { X0 = ReadUInt64(Position) };
|
return new AVec() { X0 = ReadUInt64(Position) };
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public AVec ReadVector128(long Position)
|
public AVec ReadVector128(long Position)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Read);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return new AVec()
|
return new AVec()
|
||||||
{
|
{
|
||||||
X0 = ReadUInt64(Position + 0),
|
X0 = ReadUInt64(Position + 0),
|
||||||
|
@ -233,102 +218,218 @@ namespace ChocolArm64.Memory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteSByte(long Position, sbyte Value) => WriteByte (Position, (byte)Value);
|
public sbyte ReadSByteUnchecked(long Position)
|
||||||
public void WriteInt16(long Position, short Value) => WriteUInt16(Position, (ushort)Value);
|
{
|
||||||
public void WriteInt32(long Position, int Value) => WriteUInt32(Position, (uint)Value);
|
return (sbyte)ReadByteUnchecked(Position);
|
||||||
public void WriteInt64(long Position, long Value) => WriteUInt64(Position, (ulong)Value);
|
}
|
||||||
|
|
||||||
|
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)
|
public void WriteByte(long Position, byte Value)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
||||||
#endif
|
|
||||||
|
|
||||||
*((byte*)(RamPtr + (uint)Position)) = Value;
|
WriteByteUnchecked(Position, Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void WriteUInt16(long Position, ushort Value)
|
public void WriteUInt16(long Position, ushort Value)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
EnsureAccessIsValid(Position + 0, AMemoryPerm.Write);
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
EnsureAccessIsValid(Position + 1, AMemoryPerm.Write);
|
||||||
#endif
|
|
||||||
|
|
||||||
*((ushort*)(RamPtr + (uint)Position)) = Value;
|
WriteUInt16Unchecked(Position, Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void WriteUInt32(long Position, uint Value)
|
public void WriteUInt32(long Position, uint Value)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
EnsureAccessIsValid(Position + 0, AMemoryPerm.Write);
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
EnsureAccessIsValid(Position + 3, AMemoryPerm.Write);
|
||||||
#endif
|
|
||||||
|
|
||||||
*((uint*)(RamPtr + (uint)Position)) = Value;
|
WriteUInt32Unchecked(Position, Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void WriteUInt64(long Position, ulong Value)
|
public void WriteUInt64(long Position, ulong Value)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
EnsureAccessIsValid(Position + 0, AMemoryPerm.Write);
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
EnsureAccessIsValid(Position + 7, AMemoryPerm.Write);
|
||||||
#endif
|
|
||||||
|
|
||||||
*((ulong*)(RamPtr + (uint)Position)) = Value;
|
WriteUInt64Unchecked(Position, Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void WriteVector8(long Position, AVec Value)
|
public void WriteVector8(long Position, AVec Value)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
WriteByte(Position, Value.B0);
|
WriteByte(Position, Value.B0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void WriteVector16(long Position, AVec Value)
|
public void WriteVector16(long Position, AVec Value)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
WriteUInt16(Position, Value.H0);
|
WriteUInt16(Position, Value.H0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void WriteVector32(long Position, AVec Value)
|
public void WriteVector32(long Position, AVec Value)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
WriteUInt32(Position, Value.W0);
|
WriteUInt32(Position, Value.W0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void WriteVector64(long Position, AVec Value)
|
public void WriteVector64(long Position, AVec Value)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
WriteUInt64(Position, Value.X0);
|
WriteUInt64(Position, Value.X0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void WriteVector128(long Position, AVec Value)
|
public void WriteVector128(long Position, AVec Value)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
EnsureAccessIsValid(Position, AMemoryPerm.Write);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
WriteUInt64(Position + 0, Value.X0);
|
WriteUInt64(Position + 0, Value.X0);
|
||||||
WriteUInt64(Position + 8, Value.X1);
|
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)
|
private void EnsureAccessIsValid(long Position, AMemoryPerm Perm)
|
||||||
{
|
{
|
||||||
if (!Manager.IsMapped(Position))
|
if (!Manager.IsMapped(Position))
|
||||||
|
@ -341,5 +442,20 @@ namespace ChocolArm64.Memory
|
||||||
throw new VmmAccessViolationException(Position, Perm);
|
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