Merge pull request #13 from gdkchan/master

Working....
This commit is contained in:
Dr.Hacknik 2018-03-12 11:57:47 -04:00 committed by GitHub
commit a3ce90a23d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
347 changed files with 9659 additions and 4749 deletions

View file

@ -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.

View 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
} }

View file

@ -0,0 +1,4 @@
public static class AOptimizations
{
public static bool DisableMemoryChecks = false;
}

View file

@ -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;
} }
} }

View 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;
}
}

View file

@ -0,0 +1,9 @@
namespace ChocolArm64
{
enum ATranslatedSubType
{
SubBlock,
SubTier0,
SubTier1
}
}

192
ChocolArm64/ATranslator.cs Normal file
View 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);
}
}
}
}
}

View 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>

View file

@ -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);
} }
} }
} }

View file

@ -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;

View 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;
}
}
}

View file

@ -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)
{ {

View 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;
}
}
}
}

View file

@ -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)
{ {

View 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;
}
}
}

View 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;
}
}
}

View file

@ -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;

View file

@ -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);
} }

View file

@ -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);
}
} }
} }

View file

@ -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)
{ {

View file

@ -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);
} }
} }
} }

View file

@ -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);
}
} }
} }
} }

View file

@ -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);
}
}
} }
} }

View 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);
}
}
}

View file

@ -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));
} }
} }
} }

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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);
}
}
} }
} }

View file

@ -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);
}
}
} }
} }

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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