mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-01-09 20:29:11 +00:00
Merge branch 'master' into CoOp
This commit is contained in:
commit
3c38a19fcb
97 changed files with 7282 additions and 1202 deletions
|
@ -180,6 +180,10 @@ namespace ChocolArm64
|
||||||
SetA64("0>001110<<1xxxxx101111xxxxxxxxxx", AInstEmit.Addp_V, typeof(AOpCodeSimdReg));
|
SetA64("0>001110<<1xxxxx101111xxxxxxxxxx", AInstEmit.Addp_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("000011100x110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd));
|
SetA64("000011100x110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd));
|
||||||
SetA64("01001110<<110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd));
|
SetA64("01001110<<110001101110xxxxxxxxxx", AInstEmit.Addv_V, typeof(AOpCodeSimd));
|
||||||
|
SetA64("0100111000101000010110xxxxxxxxxx", AInstEmit.Aesd_V, typeof(AOpCodeSimd));
|
||||||
|
SetA64("0100111000101000010010xxxxxxxxxx", AInstEmit.Aese_V, typeof(AOpCodeSimd));
|
||||||
|
SetA64("0100111000101000011110xxxxxxxxxx", AInstEmit.Aesimc_V, typeof(AOpCodeSimd));
|
||||||
|
SetA64("0100111000101000011010xxxxxxxxxx", AInstEmit.Aesmc_V, typeof(AOpCodeSimd));
|
||||||
SetA64("0x001110001xxxxx000111xxxxxxxxxx", AInstEmit.And_V, typeof(AOpCodeSimdReg));
|
SetA64("0x001110001xxxxx000111xxxxxxxxxx", AInstEmit.And_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x001110011xxxxx000111xxxxxxxxxx", AInstEmit.Bic_V, typeof(AOpCodeSimdReg));
|
SetA64("0x001110011xxxxx000111xxxxxxxxxx", AInstEmit.Bic_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x10111100000xxx<<x101xxxxxxxxxx", AInstEmit.Bic_Vi, typeof(AOpCodeSimdImm));
|
SetA64("0x10111100000xxx<<x101xxxxxxxxxx", AInstEmit.Bic_Vi, typeof(AOpCodeSimdImm));
|
||||||
|
@ -251,6 +255,10 @@ namespace ChocolArm64
|
||||||
SetA64("x00111100x110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt));
|
SetA64("x00111100x110000000000xxxxxxxxxx", AInstEmit.Fcvtms_Gp, typeof(AOpCodeSimdCvt));
|
||||||
SetA64("x00111100x110001000000xxxxxxxxxx", AInstEmit.Fcvtmu_Gp, typeof(AOpCodeSimdCvt));
|
SetA64("x00111100x110001000000xxxxxxxxxx", AInstEmit.Fcvtmu_Gp, typeof(AOpCodeSimdCvt));
|
||||||
SetA64("0x0011100x100001011010xxxxxxxxxx", AInstEmit.Fcvtn_V, typeof(AOpCodeSimd));
|
SetA64("0x0011100x100001011010xxxxxxxxxx", AInstEmit.Fcvtn_V, typeof(AOpCodeSimd));
|
||||||
|
SetA64("010111100x100001101010xxxxxxxxxx", AInstEmit.Fcvtns_S, typeof(AOpCodeSimd));
|
||||||
|
SetA64("0>0011100<100001101010xxxxxxxxxx", AInstEmit.Fcvtns_V, typeof(AOpCodeSimd));
|
||||||
|
SetA64("011111100x100001101010xxxxxxxxxx", AInstEmit.Fcvtnu_S, typeof(AOpCodeSimd));
|
||||||
|
SetA64("0>1011100<100001101010xxxxxxxxxx", AInstEmit.Fcvtnu_V, typeof(AOpCodeSimd));
|
||||||
SetA64("x00111100x101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt));
|
SetA64("x00111100x101000000000xxxxxxxxxx", AInstEmit.Fcvtps_Gp, typeof(AOpCodeSimdCvt));
|
||||||
SetA64("x00111100x101001000000xxxxxxxxxx", AInstEmit.Fcvtpu_Gp, typeof(AOpCodeSimdCvt));
|
SetA64("x00111100x101001000000xxxxxxxxxx", AInstEmit.Fcvtpu_Gp, typeof(AOpCodeSimdCvt));
|
||||||
SetA64("x00111100x111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt));
|
SetA64("x00111100x111000000000xxxxxxxxxx", AInstEmit.Fcvtzs_Gp, typeof(AOpCodeSimdCvt));
|
||||||
|
@ -361,6 +369,7 @@ namespace ChocolArm64
|
||||||
SetA64("0x001110<<1xxxxx011101xxxxxxxxxx", AInstEmit.Sabd_V, typeof(AOpCodeSimdReg));
|
SetA64("0x001110<<1xxxxx011101xxxxxxxxxx", AInstEmit.Sabd_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x001110<<1xxxxx011100xxxxxxxxxx", AInstEmit.Sabdl_V, typeof(AOpCodeSimdReg));
|
SetA64("0x001110<<1xxxxx011100xxxxxxxxxx", AInstEmit.Sabdl_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x001110<<100000011010xxxxxxxxxx", AInstEmit.Sadalp_V, typeof(AOpCodeSimd));
|
SetA64("0x001110<<100000011010xxxxxxxxxx", AInstEmit.Sadalp_V, typeof(AOpCodeSimd));
|
||||||
|
SetA64("0x001110<<1xxxxx000000xxxxxxxxxx", AInstEmit.Saddl_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x001110<<100000001010xxxxxxxxxx", AInstEmit.Saddlp_V, typeof(AOpCodeSimd));
|
SetA64("0x001110<<100000001010xxxxxxxxxx", AInstEmit.Saddlp_V, typeof(AOpCodeSimd));
|
||||||
SetA64("0x001110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Saddw_V, typeof(AOpCodeSimdReg));
|
SetA64("0x001110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Saddw_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("x0011110xx100010000000xxxxxxxxxx", AInstEmit.Scvtf_Gp, typeof(AOpCodeSimdCvt));
|
SetA64("x0011110xx100010000000xxxxxxxxxx", AInstEmit.Scvtf_Gp, typeof(AOpCodeSimdCvt));
|
||||||
|
@ -370,10 +379,12 @@ namespace ChocolArm64
|
||||||
SetA64("01011110000xxxxx010100xxxxxxxxxx", AInstEmit.Sha256h2_V, typeof(AOpCodeSimdReg));
|
SetA64("01011110000xxxxx010100xxxxxxxxxx", AInstEmit.Sha256h2_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0101111000101000001010xxxxxxxxxx", AInstEmit.Sha256su0_V, typeof(AOpCodeSimd));
|
SetA64("0101111000101000001010xxxxxxxxxx", AInstEmit.Sha256su0_V, typeof(AOpCodeSimd));
|
||||||
SetA64("01011110000xxxxx011000xxxxxxxxxx", AInstEmit.Sha256su1_V, typeof(AOpCodeSimdReg));
|
SetA64("01011110000xxxxx011000xxxxxxxxxx", AInstEmit.Sha256su1_V, typeof(AOpCodeSimdReg));
|
||||||
|
SetA64("0x001110<<1xxxxx000001xxxxxxxxxx", AInstEmit.Shadd_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("010111110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_S, typeof(AOpCodeSimdShImm));
|
SetA64("010111110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_S, typeof(AOpCodeSimdShImm));
|
||||||
SetA64("0x0011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_V, typeof(AOpCodeSimdShImm));
|
SetA64("0x0011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Shl_V, typeof(AOpCodeSimdShImm));
|
||||||
SetA64("0x101110<<100001001110xxxxxxxxxx", AInstEmit.Shll_V, typeof(AOpCodeSimd));
|
SetA64("0x101110<<100001001110xxxxxxxxxx", AInstEmit.Shll_V, typeof(AOpCodeSimd));
|
||||||
SetA64("0x00111100>>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm));
|
SetA64("0x00111100>>>xxx100001xxxxxxxxxx", AInstEmit.Shrn_V, typeof(AOpCodeSimdShImm));
|
||||||
|
SetA64("0x001110<<1xxxxx001001xxxxxxxxxx", AInstEmit.Shsub_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x1011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Sli_V, typeof(AOpCodeSimdShImm));
|
SetA64("0x1011110>>>>xxx010101xxxxxxxxxx", AInstEmit.Sli_V, typeof(AOpCodeSimdShImm));
|
||||||
SetA64("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg));
|
SetA64("0x001110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Smax_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x001110<<1xxxxx101001xxxxxxxxxx", AInstEmit.Smaxp_V, typeof(AOpCodeSimdReg));
|
SetA64("0x001110<<1xxxxx101001xxxxxxxxxx", AInstEmit.Smaxp_V, typeof(AOpCodeSimdReg));
|
||||||
|
@ -403,6 +414,7 @@ namespace ChocolArm64
|
||||||
SetA64("0x001110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_V, typeof(AOpCodeSimd));
|
SetA64("0x001110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_V, typeof(AOpCodeSimd));
|
||||||
SetA64("01111110<<100001001010xxxxxxxxxx", AInstEmit.Sqxtun_S, typeof(AOpCodeSimd));
|
SetA64("01111110<<100001001010xxxxxxxxxx", AInstEmit.Sqxtun_S, typeof(AOpCodeSimd));
|
||||||
SetA64("0x101110<<100001001010xxxxxxxxxx", AInstEmit.Sqxtun_V, typeof(AOpCodeSimd));
|
SetA64("0x101110<<100001001010xxxxxxxxxx", AInstEmit.Sqxtun_V, typeof(AOpCodeSimd));
|
||||||
|
SetA64("0x001110<<1xxxxx000101xxxxxxxxxx", AInstEmit.Srhadd_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x00111100>>>xxx001001xxxxxxxxxx", AInstEmit.Srshr_V, typeof(AOpCodeSimdShImm));
|
SetA64("0x00111100>>>xxx001001xxxxxxxxxx", AInstEmit.Srshr_V, typeof(AOpCodeSimdShImm));
|
||||||
SetA64("0100111101xxxxxx001001xxxxxxxxxx", AInstEmit.Srshr_V, typeof(AOpCodeSimdShImm));
|
SetA64("0100111101xxxxxx001001xxxxxxxxxx", AInstEmit.Srshr_V, typeof(AOpCodeSimdShImm));
|
||||||
SetA64("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg));
|
SetA64("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg));
|
||||||
|
@ -412,6 +424,7 @@ namespace ChocolArm64
|
||||||
SetA64("0100111101xxxxxx000001xxxxxxxxxx", AInstEmit.Sshr_V, typeof(AOpCodeSimdShImm));
|
SetA64("0100111101xxxxxx000001xxxxxxxxxx", AInstEmit.Sshr_V, typeof(AOpCodeSimdShImm));
|
||||||
SetA64("0x00111100>>>xxx000101xxxxxxxxxx", AInstEmit.Ssra_V, typeof(AOpCodeSimdShImm));
|
SetA64("0x00111100>>>xxx000101xxxxxxxxxx", AInstEmit.Ssra_V, typeof(AOpCodeSimdShImm));
|
||||||
SetA64("0100111101xxxxxx000101xxxxxxxxxx", AInstEmit.Ssra_V, typeof(AOpCodeSimdShImm));
|
SetA64("0100111101xxxxxx000101xxxxxxxxxx", AInstEmit.Ssra_V, typeof(AOpCodeSimdShImm));
|
||||||
|
SetA64("0x001110<<1xxxxx001000xxxxxxxxxx", AInstEmit.Ssubl_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x001110<<1xxxxx001100xxxxxxxxxx", AInstEmit.Ssubw_V, typeof(AOpCodeSimdReg));
|
SetA64("0x001110<<1xxxxx001100xxxxxxxxxx", AInstEmit.Ssubw_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
SetA64("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
||||||
SetA64("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
SetA64("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
||||||
|
@ -445,10 +458,13 @@ namespace ChocolArm64
|
||||||
SetA64("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd));
|
SetA64("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd));
|
||||||
SetA64("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd));
|
SetA64("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd));
|
||||||
SetA64("0x101110<<1xxxxx000001xxxxxxxxxx", AInstEmit.Uhadd_V, typeof(AOpCodeSimdReg));
|
SetA64("0x101110<<1xxxxx000001xxxxxxxxxx", AInstEmit.Uhadd_V, typeof(AOpCodeSimdReg));
|
||||||
|
SetA64("0x101110<<1xxxxx001001xxxxxxxxxx", AInstEmit.Uhsub_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x101110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Umax_V, typeof(AOpCodeSimdReg));
|
SetA64("0x101110<<1xxxxx011001xxxxxxxxxx", AInstEmit.Umax_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x101110<<1xxxxx101001xxxxxxxxxx", AInstEmit.Umaxp_V, typeof(AOpCodeSimdReg));
|
SetA64("0x101110<<1xxxxx101001xxxxxxxxxx", AInstEmit.Umaxp_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x101110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Umin_V, typeof(AOpCodeSimdReg));
|
SetA64("0x101110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Umin_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x101110<<1xxxxx101011xxxxxxxxxx", AInstEmit.Uminp_V, typeof(AOpCodeSimdReg));
|
SetA64("0x101110<<1xxxxx101011xxxxxxxxxx", AInstEmit.Uminp_V, typeof(AOpCodeSimdReg));
|
||||||
|
SetA64("0x101110<<1xxxxx100000xxxxxxxxxx", AInstEmit.Umlal_V, typeof(AOpCodeSimdReg));
|
||||||
|
SetA64("0x101110<<1xxxxx101000xxxxxxxxxx", AInstEmit.Umlsl_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
SetA64("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
||||||
SetA64("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V, typeof(AOpCodeSimdReg));
|
SetA64("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("01111110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_S, typeof(AOpCodeSimdReg));
|
SetA64("01111110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_S, typeof(AOpCodeSimdReg));
|
||||||
|
@ -457,6 +473,7 @@ namespace ChocolArm64
|
||||||
SetA64("0>101110<<1xxxxx001011xxxxxxxxxx", AInstEmit.Uqsub_V, typeof(AOpCodeSimdReg));
|
SetA64("0>101110<<1xxxxx001011xxxxxxxxxx", AInstEmit.Uqsub_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("01111110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_S, typeof(AOpCodeSimd));
|
SetA64("01111110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_S, typeof(AOpCodeSimd));
|
||||||
SetA64("0x101110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_V, typeof(AOpCodeSimd));
|
SetA64("0x101110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_V, typeof(AOpCodeSimd));
|
||||||
|
SetA64("0x101110<<1xxxxx000101xxxxxxxxxx", AInstEmit.Urhadd_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg));
|
SetA64("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm));
|
SetA64("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm));
|
||||||
SetA64("0111111101xxxxxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm));
|
SetA64("0111111101xxxxxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm));
|
||||||
|
@ -466,6 +483,7 @@ namespace ChocolArm64
|
||||||
SetA64("0>101110<<100000001110xxxxxxxxxx", AInstEmit.Usqadd_V, typeof(AOpCodeSimd));
|
SetA64("0>101110<<100000001110xxxxxxxxxx", AInstEmit.Usqadd_V, typeof(AOpCodeSimd));
|
||||||
SetA64("0x10111100>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
SetA64("0x10111100>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
||||||
SetA64("0110111101xxxxxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
SetA64("0110111101xxxxxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
||||||
|
SetA64("0x101110<<1xxxxx001000xxxxxxxxxx", AInstEmit.Usubl_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0x101110<<1xxxxx001100xxxxxxxxxx", AInstEmit.Usubw_V, typeof(AOpCodeSimdReg));
|
SetA64("0x101110<<1xxxxx001100xxxxxxxxxx", AInstEmit.Usubw_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0>001110<<0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));
|
SetA64("0>001110<<0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));
|
||||||
SetA64("0>001110<<0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg));
|
SetA64("0>001110<<0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg));
|
||||||
|
|
328
ChocolArm64/Instruction/ACryptoHelper.cs
Normal file
328
ChocolArm64/Instruction/ACryptoHelper.cs
Normal file
|
@ -0,0 +1,328 @@
|
||||||
|
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Instruction
|
||||||
|
{
|
||||||
|
static class ACryptoHelper
|
||||||
|
{
|
||||||
|
#region "LookUp Tables"
|
||||||
|
private static byte[] SBox =
|
||||||
|
{
|
||||||
|
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||||
|
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||||
|
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||||
|
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||||
|
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||||
|
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||||
|
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||||
|
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||||
|
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||||
|
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||||
|
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||||
|
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||||
|
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||||
|
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||||
|
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||||
|
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] InvSBox =
|
||||||
|
{
|
||||||
|
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||||
|
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||||
|
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||||
|
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||||
|
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||||
|
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||||
|
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||||
|
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||||
|
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||||
|
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||||
|
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||||
|
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||||
|
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||||
|
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||||
|
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||||
|
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] GFMul_02 =
|
||||||
|
{
|
||||||
|
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
|
||||||
|
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
|
||||||
|
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
|
||||||
|
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
|
||||||
|
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
|
||||||
|
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
|
||||||
|
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
|
||||||
|
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
|
||||||
|
0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
|
||||||
|
0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
|
||||||
|
0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
|
||||||
|
0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
|
||||||
|
0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
|
||||||
|
0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
|
||||||
|
0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
|
||||||
|
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] GFMul_03 =
|
||||||
|
{
|
||||||
|
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
|
||||||
|
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
|
||||||
|
0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
|
||||||
|
0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,
|
||||||
|
0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,
|
||||||
|
0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
|
||||||
|
0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,
|
||||||
|
0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,
|
||||||
|
0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
|
||||||
|
0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,
|
||||||
|
0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,
|
||||||
|
0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
|
||||||
|
0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
|
||||||
|
0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
|
||||||
|
0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
|
||||||
|
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] GFMul_09 =
|
||||||
|
{
|
||||||
|
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
||||||
|
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
|
||||||
|
0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
|
||||||
|
0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc,
|
||||||
|
0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01,
|
||||||
|
0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
|
||||||
|
0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a,
|
||||||
|
0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa,
|
||||||
|
0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
|
||||||
|
0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b,
|
||||||
|
0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0,
|
||||||
|
0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
|
||||||
|
0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed,
|
||||||
|
0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d,
|
||||||
|
0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
|
||||||
|
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] GFMul_0B =
|
||||||
|
{
|
||||||
|
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
|
||||||
|
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
|
||||||
|
0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
|
||||||
|
0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2,
|
||||||
|
0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f,
|
||||||
|
0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
|
||||||
|
0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4,
|
||||||
|
0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54,
|
||||||
|
0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
|
||||||
|
0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e,
|
||||||
|
0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5,
|
||||||
|
0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
|
||||||
|
0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68,
|
||||||
|
0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8,
|
||||||
|
0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
|
||||||
|
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] GFMul_0D =
|
||||||
|
{
|
||||||
|
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
|
||||||
|
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
|
||||||
|
0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
|
||||||
|
0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20,
|
||||||
|
0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26,
|
||||||
|
0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
|
||||||
|
0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d,
|
||||||
|
0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d,
|
||||||
|
0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
|
||||||
|
0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41,
|
||||||
|
0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a,
|
||||||
|
0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
|
||||||
|
0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc,
|
||||||
|
0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c,
|
||||||
|
0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
|
||||||
|
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] GFMul_0E =
|
||||||
|
{
|
||||||
|
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
|
||||||
|
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
|
||||||
|
0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
|
||||||
|
0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61,
|
||||||
|
0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7,
|
||||||
|
0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
|
||||||
|
0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c,
|
||||||
|
0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc,
|
||||||
|
0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
|
||||||
|
0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb,
|
||||||
|
0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0,
|
||||||
|
0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
|
||||||
|
0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6,
|
||||||
|
0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56,
|
||||||
|
0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
|
||||||
|
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] SRPerm = { 0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3 };
|
||||||
|
|
||||||
|
private static byte[] ISRPerm = { 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 };
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static Vector128<float> AESInvMixColumns(Vector128<float> op)
|
||||||
|
{
|
||||||
|
byte[] InState = new byte[16];
|
||||||
|
byte[] OutState = new byte[16];
|
||||||
|
|
||||||
|
FromVectorToByteArray(InState, ref op);
|
||||||
|
|
||||||
|
for (int Columns = 0; Columns <= 3; Columns++)
|
||||||
|
{
|
||||||
|
int Idx = Columns << 2;
|
||||||
|
|
||||||
|
byte Row0 = InState[Idx + 0]; // A, E, I, M: [Row0, Col0-Col3]
|
||||||
|
byte Row1 = InState[Idx + 1]; // B, F, J, N: [Row1, Col0-Col3]
|
||||||
|
byte Row2 = InState[Idx + 2]; // C, G, K, O: [Row2, Col0-Col3]
|
||||||
|
byte Row3 = InState[Idx + 3]; // D, H, L, P: [Row3, Col0-Col3]
|
||||||
|
|
||||||
|
OutState[Idx + 0] = (byte)((uint)GFMul_0E[Row0] ^ GFMul_0B[Row1] ^ GFMul_0D[Row2] ^ GFMul_09[Row3]);
|
||||||
|
OutState[Idx + 1] = (byte)((uint)GFMul_09[Row0] ^ GFMul_0E[Row1] ^ GFMul_0B[Row2] ^ GFMul_0D[Row3]);
|
||||||
|
OutState[Idx + 2] = (byte)((uint)GFMul_0D[Row0] ^ GFMul_09[Row1] ^ GFMul_0E[Row2] ^ GFMul_0B[Row3]);
|
||||||
|
OutState[Idx + 3] = (byte)((uint)GFMul_0B[Row0] ^ GFMul_0D[Row1] ^ GFMul_09[Row2] ^ GFMul_0E[Row3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
FromByteArrayToVector(OutState, ref op);
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector128<float> AESInvShiftRows(Vector128<float> op)
|
||||||
|
{
|
||||||
|
byte[] InState = new byte[16];
|
||||||
|
byte[] OutState = new byte[16];
|
||||||
|
|
||||||
|
FromVectorToByteArray(InState, ref op);
|
||||||
|
|
||||||
|
for (int Idx = 0; Idx <= 15; Idx++)
|
||||||
|
{
|
||||||
|
OutState[ISRPerm[Idx]] = InState[Idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
FromByteArrayToVector(OutState, ref op);
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector128<float> AESInvSubBytes(Vector128<float> op)
|
||||||
|
{
|
||||||
|
byte[] InState = new byte[16];
|
||||||
|
byte[] OutState = new byte[16];
|
||||||
|
|
||||||
|
FromVectorToByteArray(InState, ref op);
|
||||||
|
|
||||||
|
for (int Idx = 0; Idx <= 15; Idx++)
|
||||||
|
{
|
||||||
|
OutState[Idx] = InvSBox[InState[Idx]];
|
||||||
|
}
|
||||||
|
|
||||||
|
FromByteArrayToVector(OutState, ref op);
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector128<float> AESMixColumns(Vector128<float> op)
|
||||||
|
{
|
||||||
|
byte[] InState = new byte[16];
|
||||||
|
byte[] OutState = new byte[16];
|
||||||
|
|
||||||
|
FromVectorToByteArray(InState, ref op);
|
||||||
|
|
||||||
|
for (int Columns = 0; Columns <= 3; Columns++)
|
||||||
|
{
|
||||||
|
int Idx = Columns << 2;
|
||||||
|
|
||||||
|
byte Row0 = InState[Idx + 0]; // A, E, I, M: [Row0, Col0-Col3]
|
||||||
|
byte Row1 = InState[Idx + 1]; // B, F, J, N: [Row1, Col0-Col3]
|
||||||
|
byte Row2 = InState[Idx + 2]; // C, G, K, O: [Row2, Col0-Col3]
|
||||||
|
byte Row3 = InState[Idx + 3]; // D, H, L, P: [Row3, Col0-Col3]
|
||||||
|
|
||||||
|
OutState[Idx + 0] = (byte)((uint)GFMul_02[Row0] ^ GFMul_03[Row1] ^ Row2 ^ Row3);
|
||||||
|
OutState[Idx + 1] = (byte)((uint)Row0 ^ GFMul_02[Row1] ^ GFMul_03[Row2] ^ Row3);
|
||||||
|
OutState[Idx + 2] = (byte)((uint)Row0 ^ Row1 ^ GFMul_02[Row2] ^ GFMul_03[Row3]);
|
||||||
|
OutState[Idx + 3] = (byte)((uint)GFMul_03[Row0] ^ Row1 ^ Row2 ^ GFMul_02[Row3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
FromByteArrayToVector(OutState, ref op);
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector128<float> AESShiftRows(Vector128<float> op)
|
||||||
|
{
|
||||||
|
byte[] InState = new byte[16];
|
||||||
|
byte[] OutState = new byte[16];
|
||||||
|
|
||||||
|
FromVectorToByteArray(InState, ref op);
|
||||||
|
|
||||||
|
for (int Idx = 0; Idx <= 15; Idx++)
|
||||||
|
{
|
||||||
|
OutState[SRPerm[Idx]] = InState[Idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
FromByteArrayToVector(OutState, ref op);
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector128<float> AESSubBytes(Vector128<float> op)
|
||||||
|
{
|
||||||
|
byte[] InState = new byte[16];
|
||||||
|
byte[] OutState = new byte[16];
|
||||||
|
|
||||||
|
FromVectorToByteArray(InState, ref op);
|
||||||
|
|
||||||
|
for (int Idx = 0; Idx <= 15; Idx++)
|
||||||
|
{
|
||||||
|
OutState[Idx] = SBox[InState[Idx]];
|
||||||
|
}
|
||||||
|
|
||||||
|
FromByteArrayToVector(OutState, ref op);
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FromVectorToByteArray(byte[] State, ref Vector128<float> op)
|
||||||
|
{
|
||||||
|
ulong ULongLow = AVectorHelper.VectorExtractIntZx((op), (byte)0, 3);
|
||||||
|
ulong ULongHigh = AVectorHelper.VectorExtractIntZx((op), (byte)1, 3);
|
||||||
|
|
||||||
|
for (int Idx = 0; Idx <= 7; Idx++)
|
||||||
|
{
|
||||||
|
State[Idx + 0] = (byte)(ULongLow & 0xFFUL);
|
||||||
|
State[Idx + 8] = (byte)(ULongHigh & 0xFFUL);
|
||||||
|
|
||||||
|
ULongLow >>= 8;
|
||||||
|
ULongHigh >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FromByteArrayToVector(byte[] State, ref Vector128<float> op)
|
||||||
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
op = Sse.StaticCast<byte, float>(Sse2.SetVector128(
|
||||||
|
State[15], State[14], State[13], State[12],
|
||||||
|
State[11], State[10], State[9], State[8],
|
||||||
|
State[7], State[6], State[5], State[4],
|
||||||
|
State[3], State[2], State[1], State[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1032,6 +1032,11 @@ namespace ChocolArm64.Instruction
|
||||||
EmitAddLongPairwise(Context, Signed: true, Accumulate: true);
|
EmitAddLongPairwise(Context, Signed: true, Accumulate: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Saddl_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Saddlp_V(AILEmitterCtx Context)
|
public static void Saddlp_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitAddLongPairwise(Context, Signed: true, Accumulate: false);
|
EmitAddLongPairwise(Context, Signed: true, Accumulate: false);
|
||||||
|
@ -1042,6 +1047,28 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
|
EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Shadd_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitVectorBinaryOpSx(Context, () =>
|
||||||
|
{
|
||||||
|
Context.Emit(OpCodes.Add);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ldc_I4_1);
|
||||||
|
Context.Emit(OpCodes.Shr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Shsub_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitVectorBinaryOpSx(Context, () =>
|
||||||
|
{
|
||||||
|
Context.Emit(OpCodes.Sub);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ldc_I4_1);
|
||||||
|
Context.Emit(OpCodes.Shr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static void Smax_V(AILEmitterCtx Context)
|
public static void Smax_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
Type[] Types = new Type[] { typeof(long), typeof(long) };
|
Type[] Types = new Type[] { typeof(long), typeof(long) };
|
||||||
|
@ -1181,6 +1208,25 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorSaturatingNarrowOpSxZx(Context, () => { });
|
EmitVectorSaturatingNarrowOpSxZx(Context, () => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Srhadd_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitVectorBinaryOpSx(Context, () =>
|
||||||
|
{
|
||||||
|
Context.Emit(OpCodes.Add);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ldc_I4_1);
|
||||||
|
Context.Emit(OpCodes.Add);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ldc_I4_1);
|
||||||
|
Context.Emit(OpCodes.Shr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ssubl_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Sub));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Ssubw_V(AILEmitterCtx Context)
|
public static void Ssubw_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Sub));
|
EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Sub));
|
||||||
|
@ -1303,12 +1349,40 @@ namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
Context.Emit(OpCodes.Add);
|
Context.Emit(OpCodes.Add);
|
||||||
|
|
||||||
Context.EmitLdc_I4(1);
|
Context.Emit(OpCodes.Ldc_I4_1);
|
||||||
|
|
||||||
Context.Emit(OpCodes.Shr_Un);
|
Context.Emit(OpCodes.Shr_Un);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Uhsub_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitVectorBinaryOpZx(Context, () =>
|
||||||
|
{
|
||||||
|
Context.Emit(OpCodes.Sub);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ldc_I4_1);
|
||||||
|
Context.Emit(OpCodes.Shr_Un);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Umax_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
|
||||||
|
|
||||||
|
MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
|
||||||
|
|
||||||
|
EmitVectorBinaryOpZx(Context, () => Context.EmitCall(MthdInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Umaxp_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
|
||||||
|
|
||||||
|
MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
|
||||||
|
|
||||||
|
EmitVectorPairwiseOpZx(Context, () => Context.EmitCall(MthdInfo));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Umin_V(AILEmitterCtx Context)
|
public static void Umin_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
|
Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
|
||||||
|
@ -1327,22 +1401,22 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorPairwiseOpZx(Context, () => Context.EmitCall(MthdInfo));
|
EmitVectorPairwiseOpZx(Context, () => Context.EmitCall(MthdInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Umax_V(AILEmitterCtx Context)
|
public static void Umlal_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
|
EmitVectorWidenRnRmTernaryOpZx(Context, () =>
|
||||||
|
{
|
||||||
MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
|
Context.Emit(OpCodes.Mul);
|
||||||
|
Context.Emit(OpCodes.Add);
|
||||||
EmitVectorBinaryOpZx(Context, () => Context.EmitCall(MthdInfo));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Umaxp_V(AILEmitterCtx Context)
|
public static void Umlsl_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
|
EmitVectorWidenRnRmTernaryOpZx(Context, () =>
|
||||||
|
{
|
||||||
MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
|
Context.Emit(OpCodes.Mul);
|
||||||
|
Context.Emit(OpCodes.Sub);
|
||||||
EmitVectorPairwiseOpZx(Context, () => Context.EmitCall(MthdInfo));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Umull_V(AILEmitterCtx Context)
|
public static void Umull_V(AILEmitterCtx Context)
|
||||||
|
@ -1380,6 +1454,20 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorSaturatingNarrowOpZxZx(Context, () => { });
|
EmitVectorSaturatingNarrowOpZxZx(Context, () => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Urhadd_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitVectorBinaryOpZx(Context, () =>
|
||||||
|
{
|
||||||
|
Context.Emit(OpCodes.Add);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ldc_I4_1);
|
||||||
|
Context.Emit(OpCodes.Add);
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Ldc_I4_1);
|
||||||
|
Context.Emit(OpCodes.Shr_Un);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static void Usqadd_S(AILEmitterCtx Context)
|
public static void Usqadd_S(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitScalarSaturatingBinaryOpZx(Context, SaturatingFlags.Accumulate);
|
EmitScalarSaturatingBinaryOpZx(Context, SaturatingFlags.Accumulate);
|
||||||
|
@ -1390,6 +1478,11 @@ namespace ChocolArm64.Instruction
|
||||||
EmitVectorSaturatingBinaryOpZx(Context, SaturatingFlags.Accumulate);
|
EmitVectorSaturatingBinaryOpZx(Context, SaturatingFlags.Accumulate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Usubl_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Usubw_V(AILEmitterCtx Context)
|
public static void Usubw_V(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
|
EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
|
||||||
|
|
54
ChocolArm64/Instruction/AInstEmitSimdCrypto.cs
Normal file
54
ChocolArm64/Instruction/AInstEmitSimdCrypto.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using ChocolArm64.Decoder;
|
||||||
|
using ChocolArm64.Translation;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Instruction
|
||||||
|
{
|
||||||
|
static partial class AInstEmit
|
||||||
|
{
|
||||||
|
public static void Aesd_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
Context.EmitLdvec(Op.Rd);
|
||||||
|
Context.EmitLdvec(Op.Rn);
|
||||||
|
|
||||||
|
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Decrypt));
|
||||||
|
|
||||||
|
Context.EmitStvec(Op.Rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Aese_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
Context.EmitLdvec(Op.Rd);
|
||||||
|
Context.EmitLdvec(Op.Rn);
|
||||||
|
|
||||||
|
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Encrypt));
|
||||||
|
|
||||||
|
Context.EmitStvec(Op.Rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Aesimc_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
Context.EmitLdvec(Op.Rn);
|
||||||
|
|
||||||
|
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InverseMixColumns));
|
||||||
|
|
||||||
|
Context.EmitStvec(Op.Rd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Aesmc_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
Context.EmitLdvec(Op.Rn);
|
||||||
|
|
||||||
|
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MixColumns));
|
||||||
|
|
||||||
|
Context.EmitStvec(Op.Rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -106,6 +106,26 @@ namespace ChocolArm64.Instruction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Fcvtns_S(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitFcvtn(Context, Signed: true, Scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcvtns_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitFcvtn(Context, Signed: true, Scalar: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcvtnu_S(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitFcvtn(Context, Signed: false, Scalar: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fcvtnu_V(AILEmitterCtx Context)
|
||||||
|
{
|
||||||
|
EmitFcvtn(Context, Signed: false, Scalar: false);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Fcvtps_Gp(AILEmitterCtx Context)
|
public static void Fcvtps_Gp(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitFcvt_s_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Ceiling)));
|
EmitFcvt_s_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Ceiling)));
|
||||||
|
@ -250,6 +270,54 @@ namespace ChocolArm64.Instruction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitFcvtn(AILEmitterCtx Context, bool Signed, bool Scalar)
|
||||||
|
{
|
||||||
|
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||||
|
|
||||||
|
int SizeF = Op.Size & 1;
|
||||||
|
int SizeI = SizeF + 2;
|
||||||
|
|
||||||
|
int Bytes = Op.GetBitsCount() >> 3;
|
||||||
|
int Elems = !Scalar ? Bytes >> SizeI : 1;
|
||||||
|
|
||||||
|
if (Scalar && (SizeF == 0))
|
||||||
|
{
|
||||||
|
EmitVectorZeroLowerTmp(Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int Index = 0; Index < Elems; Index++)
|
||||||
|
{
|
||||||
|
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||||
|
|
||||||
|
EmitRoundMathCall(Context, MidpointRounding.ToEven);
|
||||||
|
|
||||||
|
if (SizeF == 0)
|
||||||
|
{
|
||||||
|
AVectorHelper.EmitCall(Context, Signed
|
||||||
|
? nameof(AVectorHelper.SatF32ToS32)
|
||||||
|
: nameof(AVectorHelper.SatF32ToU32));
|
||||||
|
|
||||||
|
Context.Emit(OpCodes.Conv_U8);
|
||||||
|
}
|
||||||
|
else /* if (SizeF == 1) */
|
||||||
|
{
|
||||||
|
AVectorHelper.EmitCall(Context, Signed
|
||||||
|
? nameof(AVectorHelper.SatF64ToS64)
|
||||||
|
: nameof(AVectorHelper.SatF64ToU64));
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitVectorInsertTmp(Context, Index, SizeI);
|
||||||
|
}
|
||||||
|
|
||||||
|
Context.EmitLdvectmp();
|
||||||
|
Context.EmitStvec(Op.Rd);
|
||||||
|
|
||||||
|
if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
|
||||||
|
{
|
||||||
|
EmitVectorZeroUpper(Context, Op.Rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitFcvt_s_Gp(AILEmitterCtx Context, Action Emit)
|
private static void EmitFcvt_s_Gp(AILEmitterCtx Context, Action Emit)
|
||||||
{
|
{
|
||||||
EmitFcvt___Gp(Context, Emit, true);
|
EmitFcvt___Gp(Context, Emit, true);
|
||||||
|
|
|
@ -410,6 +410,42 @@ namespace ChocolArm64.Instruction
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region "Aes"
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector128<float> Decrypt(Vector128<float> value, Vector128<float> roundKey)
|
||||||
|
{
|
||||||
|
if (!Sse.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ACryptoHelper.AESInvSubBytes(ACryptoHelper.AESInvShiftRows(Sse.Xor(value, roundKey)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector128<float> Encrypt(Vector128<float> value, Vector128<float> roundKey)
|
||||||
|
{
|
||||||
|
if (!Sse.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ACryptoHelper.AESSubBytes(ACryptoHelper.AESShiftRows(Sse.Xor(value, roundKey)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector128<float> InverseMixColumns(Vector128<float> value)
|
||||||
|
{
|
||||||
|
return ACryptoHelper.AESInvMixColumns(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Vector128<float> MixColumns(Vector128<float> value)
|
||||||
|
{
|
||||||
|
return ACryptoHelper.AESMixColumns(value);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region "Sha256"
|
#region "Sha256"
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Vector128<float> HashLower(Vector128<float> hash_abcd, Vector128<float> hash_efgh, Vector128<float> wk)
|
public static Vector128<float> HashLower(Vector128<float> hash_abcd, Vector128<float> hash_efgh, Vector128<float> wk)
|
||||||
|
|
68
Ryujinx.Graphics/Gal/GalFrameBufferFormat.cs
Normal file
68
Ryujinx.Graphics/Gal/GalFrameBufferFormat.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalFrameBufferFormat
|
||||||
|
{
|
||||||
|
Bitmap = 0x1c,
|
||||||
|
Unknown1D = 0x1d,
|
||||||
|
RGBA32Float = 0xc0,
|
||||||
|
RGBA32Sint = 0xc1,
|
||||||
|
RGBA32Uint = 0xc2,
|
||||||
|
RGBX32Float = 0xc3,
|
||||||
|
RGBX32Sint = 0xc4,
|
||||||
|
RGBX32Uint = 0xc5,
|
||||||
|
RGBA16Unorm = 0xc6,
|
||||||
|
RGBA16Snorm = 0xc7,
|
||||||
|
RGBA16Sint = 0xc8,
|
||||||
|
RGBA16Uint = 0xc9,
|
||||||
|
RGBA16Float = 0xca,
|
||||||
|
RG32Float = 0xcb,
|
||||||
|
RG32Sint = 0xcc,
|
||||||
|
RG32Uint = 0xcd,
|
||||||
|
RGBX16Float = 0xce,
|
||||||
|
BGRA8Unorm = 0xcf,
|
||||||
|
BGRA8Srgb = 0xd0,
|
||||||
|
RGB10A2Unorm = 0xd1,
|
||||||
|
RGB10A2Uint = 0xd2,
|
||||||
|
RGBA8Unorm = 0xd5,
|
||||||
|
RGBA8Srgb = 0xd6,
|
||||||
|
RGBA8Snorm = 0xd7,
|
||||||
|
RGBA8Sint = 0xd8,
|
||||||
|
RGBA8Uint = 0xd9,
|
||||||
|
RG16Unorm = 0xda,
|
||||||
|
RG16Snorm = 0xdb,
|
||||||
|
RG16Sint = 0xdc,
|
||||||
|
RG16Uint = 0xdd,
|
||||||
|
RG16Float = 0xde,
|
||||||
|
BGR10A2Unorm = 0xdf,
|
||||||
|
R11G11B10Float = 0xe0,
|
||||||
|
R32Sint = 0xe3,
|
||||||
|
R32Uint = 0xe4,
|
||||||
|
R32Float = 0xe5,
|
||||||
|
BGRX8Unorm = 0xe6,
|
||||||
|
BGRX8Srgb = 0xe7,
|
||||||
|
B5G6R5Unorm = 0xe8,
|
||||||
|
BGR5A1Unorm = 0xe9,
|
||||||
|
RG8Unorm = 0xea,
|
||||||
|
RG8Snorm = 0xeb,
|
||||||
|
RG8Sint = 0xec,
|
||||||
|
RG8Uint = 0xed,
|
||||||
|
R16Unorm = 0xee,
|
||||||
|
R16Snorm = 0xef,
|
||||||
|
R16Sint = 0xf0,
|
||||||
|
R16Uint = 0xf1,
|
||||||
|
R16Float = 0xf2,
|
||||||
|
R8Unorm = 0xf3,
|
||||||
|
R8Snorm = 0xf4,
|
||||||
|
R8Sint = 0xf5,
|
||||||
|
R8Uint = 0xf6,
|
||||||
|
A8Unorm = 0xf7,
|
||||||
|
BGR5X1Unorm = 0xf8,
|
||||||
|
RGBX8Unorm = 0xf9,
|
||||||
|
RGBX8Srgb = 0xfa,
|
||||||
|
BGR5X1UnormUnknownFB = 0xfb,
|
||||||
|
BGR5X1UnormUnknownFC = 0xfc,
|
||||||
|
BGRX8UnormUnknownFD = 0xfd,
|
||||||
|
BGRX8UnormUnknownFE = 0xfe,
|
||||||
|
Y32UintUnknownFF = 0xff
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,25 @@
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public struct GalTexture
|
public struct GalImage
|
||||||
{
|
{
|
||||||
public int Width;
|
public int Width;
|
||||||
public int Height;
|
public int Height;
|
||||||
|
|
||||||
public GalTextureFormat Format;
|
public GalImageFormat Format;
|
||||||
|
|
||||||
public GalTextureSource XSource;
|
public GalTextureSource XSource;
|
||||||
public GalTextureSource YSource;
|
public GalTextureSource YSource;
|
||||||
public GalTextureSource ZSource;
|
public GalTextureSource ZSource;
|
||||||
public GalTextureSource WSource;
|
public GalTextureSource WSource;
|
||||||
|
|
||||||
public GalTexture(
|
public GalImage(
|
||||||
int Width,
|
int Width,
|
||||||
int Height,
|
int Height,
|
||||||
GalTextureFormat Format,
|
GalImageFormat Format,
|
||||||
GalTextureSource XSource,
|
GalTextureSource XSource = GalTextureSource.Red,
|
||||||
GalTextureSource YSource,
|
GalTextureSource YSource = GalTextureSource.Green,
|
||||||
GalTextureSource ZSource,
|
GalTextureSource ZSource = GalTextureSource.Blue,
|
||||||
GalTextureSource WSource)
|
GalTextureSource WSource = GalTextureSource.Alpha)
|
||||||
{
|
{
|
||||||
this.Width = Width;
|
this.Width = Width;
|
||||||
this.Height = Height;
|
this.Height = Height;
|
204
Ryujinx.Graphics/Gal/GalImageFormat.cs
Normal file
204
Ryujinx.Graphics/Gal/GalImageFormat.cs
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
//These are Vulkan-based enumerations, do not take them as Tegra values
|
||||||
|
public enum GalImageFormat
|
||||||
|
{
|
||||||
|
Undefined = 0,
|
||||||
|
|
||||||
|
R4G4_UNORM_PACK8 = 1,
|
||||||
|
R4G4B4A4_UNORM_PACK16 = 2,
|
||||||
|
B4G4R4A4_UNORM_PACK16 = 3,
|
||||||
|
R5G6B5_UNORM_PACK16 = 4,
|
||||||
|
B5G6R5_UNORM_PACK16 = 5,
|
||||||
|
R5G5B5A1_UNORM_PACK16 = 6,
|
||||||
|
B5G5R5A1_UNORM_PACK16 = 7,
|
||||||
|
A1R5G5B5_UNORM_PACK16 = 8,
|
||||||
|
R8_UNORM = 9,
|
||||||
|
R8_SNORM = 10,
|
||||||
|
R8_USCALED = 11,
|
||||||
|
R8_SSCALED = 12,
|
||||||
|
R8_UINT = 13,
|
||||||
|
R8_SINT = 14,
|
||||||
|
R8_SRGB = 15,
|
||||||
|
R8G8_UNORM = 16,
|
||||||
|
R8G8_SNORM = 17,
|
||||||
|
R8G8_USCALED = 18,
|
||||||
|
R8G8_SSCALED = 19,
|
||||||
|
R8G8_UINT = 20,
|
||||||
|
R8G8_SINT = 21,
|
||||||
|
R8G8_SRGB = 22,
|
||||||
|
R8G8B8_UNORM = 23,
|
||||||
|
R8G8B8_SNORM = 24,
|
||||||
|
R8G8B8_USCALED = 25,
|
||||||
|
R8G8B8_SSCALED = 26,
|
||||||
|
R8G8B8_UINT = 27,
|
||||||
|
R8G8B8_SINT = 28,
|
||||||
|
R8G8B8_SRGB = 29,
|
||||||
|
B8G8R8_UNORM = 30,
|
||||||
|
B8G8R8_SNORM = 31,
|
||||||
|
B8G8R8_USCALED = 32,
|
||||||
|
B8G8R8_SSCALED = 33,
|
||||||
|
B8G8R8_UINT = 34,
|
||||||
|
B8G8R8_SINT = 35,
|
||||||
|
B8G8R8_SRGB = 36,
|
||||||
|
R8G8B8A8_UNORM = 37,
|
||||||
|
R8G8B8A8_SNORM = 38,
|
||||||
|
R8G8B8A8_USCALED = 39,
|
||||||
|
R8G8B8A8_SSCALED = 40,
|
||||||
|
R8G8B8A8_UINT = 41,
|
||||||
|
R8G8B8A8_SINT = 42,
|
||||||
|
R8G8B8A8_SRGB = 43,
|
||||||
|
B8G8R8A8_UNORM = 44,
|
||||||
|
B8G8R8A8_SNORM = 45,
|
||||||
|
B8G8R8A8_USCALED = 46,
|
||||||
|
B8G8R8A8_SSCALED = 47,
|
||||||
|
B8G8R8A8_UINT = 48,
|
||||||
|
B8G8R8A8_SINT = 49,
|
||||||
|
B8G8R8A8_SRGB = 50,
|
||||||
|
A8B8G8R8_UNORM_PACK32 = 51,
|
||||||
|
A8B8G8R8_SNORM_PACK32 = 52,
|
||||||
|
A8B8G8R8_USCALED_PACK32 = 53,
|
||||||
|
A8B8G8R8_SSCALED_PACK32 = 54,
|
||||||
|
A8B8G8R8_UINT_PACK32 = 55,
|
||||||
|
A8B8G8R8_SINT_PACK32 = 56,
|
||||||
|
A8B8G8R8_SRGB_PACK32 = 57,
|
||||||
|
A2R10G10B10_UNORM_PACK32 = 58,
|
||||||
|
A2R10G10B10_SNORM_PACK32 = 59,
|
||||||
|
A2R10G10B10_USCALED_PACK32 = 60,
|
||||||
|
A2R10G10B10_SSCALED_PACK32 = 61,
|
||||||
|
A2R10G10B10_UINT_PACK32 = 62,
|
||||||
|
A2R10G10B10_SINT_PACK32 = 63,
|
||||||
|
A2B10G10R10_UNORM_PACK32 = 64,
|
||||||
|
A2B10G10R10_SNORM_PACK32 = 65,
|
||||||
|
A2B10G10R10_USCALED_PACK32 = 66,
|
||||||
|
A2B10G10R10_SSCALED_PACK32 = 67,
|
||||||
|
A2B10G10R10_UINT_PACK32 = 68,
|
||||||
|
A2B10G10R10_SINT_PACK32 = 69,
|
||||||
|
R16_UNORM = 70,
|
||||||
|
R16_SNORM = 71,
|
||||||
|
R16_USCALED = 72,
|
||||||
|
R16_SSCALED = 73,
|
||||||
|
R16_UINT = 74,
|
||||||
|
R16_SINT = 75,
|
||||||
|
R16_SFLOAT = 76,
|
||||||
|
R16G16_UNORM = 77,
|
||||||
|
R16G16_SNORM = 78,
|
||||||
|
R16G16_USCALED = 79,
|
||||||
|
R16G16_SSCALED = 80,
|
||||||
|
R16G16_UINT = 81,
|
||||||
|
R16G16_SINT = 82,
|
||||||
|
R16G16_SFLOAT = 83,
|
||||||
|
R16G16B16_UNORM = 84,
|
||||||
|
R16G16B16_SNORM = 85,
|
||||||
|
R16G16B16_USCALED = 86,
|
||||||
|
R16G16B16_SSCALED = 87,
|
||||||
|
R16G16B16_UINT = 88,
|
||||||
|
R16G16B16_SINT = 89,
|
||||||
|
R16G16B16_SFLOAT = 90,
|
||||||
|
R16G16B16A16_UNORM = 91,
|
||||||
|
R16G16B16A16_SNORM = 92,
|
||||||
|
R16G16B16A16_USCALED = 93,
|
||||||
|
R16G16B16A16_SSCALED = 94,
|
||||||
|
R16G16B16A16_UINT = 95,
|
||||||
|
R16G16B16A16_SINT = 96,
|
||||||
|
R16G16B16A16_SFLOAT = 97,
|
||||||
|
R32_UINT = 98,
|
||||||
|
R32_SINT = 99,
|
||||||
|
R32_SFLOAT = 100,
|
||||||
|
R32G32_UINT = 101,
|
||||||
|
R32G32_SINT = 102,
|
||||||
|
R32G32_SFLOAT = 103,
|
||||||
|
R32G32B32_UINT = 104,
|
||||||
|
R32G32B32_SINT = 105,
|
||||||
|
R32G32B32_SFLOAT = 106,
|
||||||
|
R32G32B32A32_UINT = 107,
|
||||||
|
R32G32B32A32_SINT = 108,
|
||||||
|
R32G32B32A32_SFLOAT = 109,
|
||||||
|
R64_UINT = 110,
|
||||||
|
R64_SINT = 111,
|
||||||
|
R64_SFLOAT = 112,
|
||||||
|
R64G64_UINT = 113,
|
||||||
|
R64G64_SINT = 114,
|
||||||
|
R64G64_SFLOAT = 115,
|
||||||
|
R64G64B64_UINT = 116,
|
||||||
|
R64G64B64_SINT = 117,
|
||||||
|
R64G64B64_SFLOAT = 118,
|
||||||
|
R64G64B64A64_UINT = 119,
|
||||||
|
R64G64B64A64_SINT = 120,
|
||||||
|
R64G64B64A64_SFLOAT = 121,
|
||||||
|
B10G11R11_UFLOAT_PACK32 = 122,
|
||||||
|
E5B9G9R9_UFLOAT_PACK32 = 123,
|
||||||
|
D16_UNORM = 124,
|
||||||
|
X8_D24_UNORM_PACK32 = 125,
|
||||||
|
D32_SFLOAT = 126,
|
||||||
|
S8_UINT = 127,
|
||||||
|
D16_UNORM_S8_UINT = 128,
|
||||||
|
D24_UNORM_S8_UINT = 129,
|
||||||
|
D32_SFLOAT_S8_UINT = 130,
|
||||||
|
BC1_RGB_UNORM_BLOCK = 131,
|
||||||
|
BC1_RGB_SRGB_BLOCK = 132,
|
||||||
|
BC1_RGBA_UNORM_BLOCK = 133,
|
||||||
|
BC1_RGBA_SRGB_BLOCK = 134,
|
||||||
|
BC2_UNORM_BLOCK = 135,
|
||||||
|
BC2_SRGB_BLOCK = 136,
|
||||||
|
BC3_UNORM_BLOCK = 137,
|
||||||
|
BC3_SRGB_BLOCK = 138,
|
||||||
|
BC4_UNORM_BLOCK = 139,
|
||||||
|
BC4_SNORM_BLOCK = 140,
|
||||||
|
BC5_UNORM_BLOCK = 141,
|
||||||
|
BC5_SNORM_BLOCK = 142,
|
||||||
|
BC6H_UFLOAT_BLOCK = 143,
|
||||||
|
BC6H_SFLOAT_BLOCK = 144,
|
||||||
|
BC7_UNORM_BLOCK = 145,
|
||||||
|
BC7_SRGB_BLOCK = 146,
|
||||||
|
ETC2_R8G8B8_UNORM_BLOCK = 147,
|
||||||
|
ETC2_R8G8B8_SRGB_BLOCK = 148,
|
||||||
|
ETC2_R8G8B8A1_UNORM_BLOCK = 149,
|
||||||
|
ETC2_R8G8B8A1_SRGB_BLOCK = 150,
|
||||||
|
ETC2_R8G8B8A8_UNORM_BLOCK = 151,
|
||||||
|
ETC2_R8G8B8A8_SRGB_BLOCK = 152,
|
||||||
|
EAC_R11_UNORM_BLOCK = 153,
|
||||||
|
EAC_R11_SNORM_BLOCK = 154,
|
||||||
|
EAC_R11G11_UNORM_BLOCK = 155,
|
||||||
|
EAC_R11G11_SNORM_BLOCK = 156,
|
||||||
|
|
||||||
|
ASTC_BEGIN = ASTC_4x4_UNORM_BLOCK,
|
||||||
|
|
||||||
|
ASTC_4x4_UNORM_BLOCK = 157,
|
||||||
|
ASTC_4x4_SRGB_BLOCK = 158,
|
||||||
|
ASTC_5x4_UNORM_BLOCK = 159,
|
||||||
|
ASTC_5x4_SRGB_BLOCK = 160,
|
||||||
|
ASTC_5x5_UNORM_BLOCK = 161,
|
||||||
|
ASTC_5x5_SRGB_BLOCK = 162,
|
||||||
|
ASTC_6x5_UNORM_BLOCK = 163,
|
||||||
|
ASTC_6x5_SRGB_BLOCK = 164,
|
||||||
|
ASTC_6x6_UNORM_BLOCK = 165,
|
||||||
|
ASTC_6x6_SRGB_BLOCK = 166,
|
||||||
|
ASTC_8x5_UNORM_BLOCK = 167,
|
||||||
|
ASTC_8x5_SRGB_BLOCK = 168,
|
||||||
|
ASTC_8x6_UNORM_BLOCK = 169,
|
||||||
|
ASTC_8x6_SRGB_BLOCK = 170,
|
||||||
|
ASTC_8x8_UNORM_BLOCK = 171,
|
||||||
|
ASTC_8x8_SRGB_BLOCK = 172,
|
||||||
|
ASTC_10x5_UNORM_BLOCK = 173,
|
||||||
|
ASTC_10x5_SRGB_BLOCK = 174,
|
||||||
|
ASTC_10x6_UNORM_BLOCK = 175,
|
||||||
|
ASTC_10x6_SRGB_BLOCK = 176,
|
||||||
|
ASTC_10x8_UNORM_BLOCK = 177,
|
||||||
|
ASTC_10x8_SRGB_BLOCK = 178,
|
||||||
|
ASTC_10x10_UNORM_BLOCK = 179,
|
||||||
|
ASTC_10x10_SRGB_BLOCK = 180,
|
||||||
|
ASTC_12x10_UNORM_BLOCK = 181,
|
||||||
|
ASTC_12x10_SRGB_BLOCK = 182,
|
||||||
|
ASTC_12x12_UNORM_BLOCK = 183,
|
||||||
|
ASTC_12x12_SRGB_BLOCK = 184,
|
||||||
|
|
||||||
|
ASTC_END = ASTC_12x12_SRGB_BLOCK,
|
||||||
|
|
||||||
|
REVERSED_BEGIN,
|
||||||
|
|
||||||
|
R4G4B4A4_UNORM_PACK16_REVERSED = REVERSED_BEGIN,
|
||||||
|
|
||||||
|
REVERSED_END
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,8 @@
|
||||||
public bool Enabled;
|
public bool Enabled;
|
||||||
public int Stride;
|
public int Stride;
|
||||||
public long VboKey;
|
public long VboKey;
|
||||||
|
public bool Instanced;
|
||||||
|
public int Divisor;
|
||||||
public GalVertexAttrib[] Attribs;
|
public GalVertexAttrib[] Attribs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +24,8 @@
|
||||||
public float FlipX;
|
public float FlipX;
|
||||||
public float FlipY;
|
public float FlipY;
|
||||||
|
|
||||||
|
public int Instance;
|
||||||
|
|
||||||
public GalFrontFace FrontFace;
|
public GalFrontFace FrontFace;
|
||||||
|
|
||||||
public bool CullFaceEnabled;
|
public bool CullFaceEnabled;
|
||||||
|
|
|
@ -4,11 +4,13 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
R32G32B32A32 = 0x1,
|
R32G32B32A32 = 0x1,
|
||||||
R16G16B16A16 = 0x3,
|
R16G16B16A16 = 0x3,
|
||||||
|
R32G32 = 0x4,
|
||||||
A8B8G8R8 = 0x8,
|
A8B8G8R8 = 0x8,
|
||||||
A2B10G10R10 = 0x9,
|
A2B10G10R10 = 0x9,
|
||||||
R32 = 0xf,
|
R32 = 0xf,
|
||||||
BC6H_SF16 = 0x10,
|
BC6H_SF16 = 0x10,
|
||||||
BC6H_UF16 = 0x11,
|
BC6H_UF16 = 0x11,
|
||||||
|
A4B4G4R4 = 0x12,
|
||||||
A1B5G5R5 = 0x14,
|
A1B5G5R5 = 0x14,
|
||||||
B5G6R5 = 0x15,
|
B5G6R5 = 0x15,
|
||||||
BC7U = 0x17,
|
BC7U = 0x17,
|
||||||
|
@ -23,6 +25,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
BC5 = 0x28,
|
BC5 = 0x28,
|
||||||
Z24S8 = 0x29,
|
Z24S8 = 0x29,
|
||||||
ZF32 = 0x2f,
|
ZF32 = 0x2f,
|
||||||
|
ZF32_X24S8 = 0x30,
|
||||||
Astc2D4x4 = 0x40,
|
Astc2D4x4 = 0x40,
|
||||||
Astc2D5x5 = 0x41,
|
Astc2D5x5 = 0x41,
|
||||||
Astc2D6x6 = 0x42,
|
Astc2D6x6 = 0x42,
|
||||||
|
|
13
Ryujinx.Graphics/Gal/GalTextureType.cs
Normal file
13
Ryujinx.Graphics/Gal/GalTextureType.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalTextureType
|
||||||
|
{
|
||||||
|
Snorm = 1,
|
||||||
|
Unorm = 2,
|
||||||
|
Sint = 3,
|
||||||
|
Uint = 4,
|
||||||
|
Snorm_Force_Fp16 = 5,
|
||||||
|
Unorm_Force_Fp16 = 6,
|
||||||
|
Float = 7
|
||||||
|
}
|
||||||
|
}
|
16
Ryujinx.Graphics/Gal/GalZetaFormat.cs
Normal file
16
Ryujinx.Graphics/Gal/GalZetaFormat.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public enum GalZetaFormat
|
||||||
|
{
|
||||||
|
Z32Float = 0x0a,
|
||||||
|
Z16Unorm = 0x13,
|
||||||
|
S8Z24Unorm = 0x14,
|
||||||
|
Z24X8Unorm = 0x15,
|
||||||
|
Z24S8Unorm = 0x16,
|
||||||
|
Z24C8Unorm = 0x18,
|
||||||
|
Z32S8X24Float = 0x19,
|
||||||
|
Z24X8S8C8X16Unorm = 0x1d,
|
||||||
|
Z32X8C8X16Float = 0x1e,
|
||||||
|
Z32S8C8X16Float = 0x1f
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,13 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public interface IGalFrameBuffer
|
public interface IGalFrameBuffer
|
||||||
{
|
{
|
||||||
void Create(long Key, int Width, int Height);
|
void BindColor(long Key, int Attachment);
|
||||||
|
|
||||||
void Bind(long Key);
|
void UnbindColor(int Attachment);
|
||||||
|
|
||||||
|
void BindZeta(long Key);
|
||||||
|
|
||||||
|
void UnbindZeta();
|
||||||
|
|
||||||
void BindTexture(long Key, int Index);
|
void BindTexture(long Key, int Index);
|
||||||
|
|
||||||
|
@ -14,6 +18,8 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
void Set(byte[] Data, int Width, int Height);
|
void Set(byte[] Data, int Width, int Height);
|
||||||
|
|
||||||
|
void SetMap(int[] Map);
|
||||||
|
|
||||||
void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom);
|
void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom);
|
||||||
|
|
||||||
void SetWindowSize(int Width, int Height);
|
void SetWindowSize(int Width, int Height);
|
||||||
|
@ -40,7 +46,6 @@ namespace Ryujinx.Graphics.Gal
|
||||||
long Key,
|
long Key,
|
||||||
int Width,
|
int Width,
|
||||||
int Height,
|
int Height,
|
||||||
GalTextureFormat Format,
|
|
||||||
byte[] Buffer);
|
byte[] Buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
void ClearBuffers(
|
void ClearBuffers(
|
||||||
GalClearBufferFlags Flags,
|
GalClearBufferFlags Flags,
|
||||||
|
int Attachment,
|
||||||
float Red, float Green, float Blue, float Alpha,
|
float Red, float Green, float Blue, float Alpha,
|
||||||
float Depth,
|
float Depth,
|
||||||
int Stencil);
|
int Stencil);
|
||||||
|
|
|
@ -11,8 +11,6 @@ namespace Ryujinx.Graphics.Gal
|
||||||
IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long Key);
|
IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long Key);
|
||||||
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key);
|
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key);
|
||||||
|
|
||||||
void EnsureTextureBinding(string UniformName, int Value);
|
|
||||||
|
|
||||||
void Bind(long Key);
|
void Bind(long Key);
|
||||||
|
|
||||||
void Unbind(GalShaderType Type);
|
void Unbind(GalShaderType Type);
|
||||||
|
|
|
@ -5,9 +5,11 @@ namespace Ryujinx.Graphics.Gal
|
||||||
void LockCache();
|
void LockCache();
|
||||||
void UnlockCache();
|
void UnlockCache();
|
||||||
|
|
||||||
void Create(long Key, byte[] Data, GalTexture Texture);
|
void Create(long Key, byte[] Data, GalImage Image);
|
||||||
|
|
||||||
bool TryGetCachedTexture(long Key, long DataSize, out GalTexture Texture);
|
void CreateFb(long Key, long Size, GalImage Image);
|
||||||
|
|
||||||
|
bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image);
|
||||||
|
|
||||||
void Bind(long Key, int Index);
|
void Bind(long Key, int Index);
|
||||||
|
|
||||||
|
|
279
Ryujinx.Graphics/Gal/ImageFormatConverter.cs
Normal file
279
Ryujinx.Graphics/Gal/ImageFormatConverter.cs
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public static class ImageFormatConverter
|
||||||
|
{
|
||||||
|
public static GalImageFormat ConvertTexture(
|
||||||
|
GalTextureFormat Format,
|
||||||
|
GalTextureType RType,
|
||||||
|
GalTextureType GType,
|
||||||
|
GalTextureType BType,
|
||||||
|
GalTextureType AType)
|
||||||
|
{
|
||||||
|
if (RType != GType || RType != BType || RType != AType)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Per component types are not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
GalTextureType Type = RType;
|
||||||
|
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case GalTextureType.Snorm:
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_SNORM;
|
||||||
|
case GalTextureFormat.A8B8G8R8: return GalImageFormat.A8B8G8R8_SNORM_PACK32;
|
||||||
|
case GalTextureFormat.A2B10G10R10: return GalImageFormat.A2B10G10R10_SNORM_PACK32;
|
||||||
|
case GalTextureFormat.G8R8: return GalImageFormat.R8G8_SNORM;
|
||||||
|
case GalTextureFormat.R16: return GalImageFormat.R16_SNORM;
|
||||||
|
case GalTextureFormat.R8: return GalImageFormat.R8_SNORM;
|
||||||
|
case GalTextureFormat.BC4: return GalImageFormat.BC4_SNORM_BLOCK;
|
||||||
|
case GalTextureFormat.BC5: return GalImageFormat.BC5_SNORM_BLOCK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalTextureType.Unorm:
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_UNORM;
|
||||||
|
case GalTextureFormat.A8B8G8R8: return GalImageFormat.A8B8G8R8_UNORM_PACK32;
|
||||||
|
case GalTextureFormat.A2B10G10R10: return GalImageFormat.A2B10G10R10_UNORM_PACK32;
|
||||||
|
case GalTextureFormat.A4B4G4R4: return GalImageFormat.R4G4B4A4_UNORM_PACK16_REVERSED;
|
||||||
|
case GalTextureFormat.A1B5G5R5: return GalImageFormat.A1R5G5B5_UNORM_PACK16;
|
||||||
|
case GalTextureFormat.B5G6R5: return GalImageFormat.B5G6R5_UNORM_PACK16;
|
||||||
|
case GalTextureFormat.BC7U: return GalImageFormat.BC7_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.G8R8: return GalImageFormat.R8G8_UNORM;
|
||||||
|
case GalTextureFormat.R16: return GalImageFormat.R16_UNORM;
|
||||||
|
case GalTextureFormat.R8: return GalImageFormat.R8_UNORM;
|
||||||
|
case GalTextureFormat.BC1: return GalImageFormat.BC1_RGBA_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.BC2: return GalImageFormat.BC2_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.BC3: return GalImageFormat.BC3_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.BC4: return GalImageFormat.BC4_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.BC5: return GalImageFormat.BC5_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Z24S8: return GalImageFormat.D24_UNORM_S8_UINT;
|
||||||
|
case GalTextureFormat.ZF32_X24S8: return GalImageFormat.D32_SFLOAT_S8_UINT;
|
||||||
|
case GalTextureFormat.Astc2D4x4: return GalImageFormat.ASTC_4x4_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D5x5: return GalImageFormat.ASTC_5x5_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D6x6: return GalImageFormat.ASTC_6x6_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D8x8: return GalImageFormat.ASTC_8x8_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D10x10: return GalImageFormat.ASTC_10x10_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D12x12: return GalImageFormat.ASTC_12x12_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D5x4: return GalImageFormat.ASTC_5x4_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D6x5: return GalImageFormat.ASTC_6x5_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D8x6: return GalImageFormat.ASTC_8x6_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D10x8: return GalImageFormat.ASTC_10x8_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D12x10: return GalImageFormat.ASTC_12x10_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D8x5: return GalImageFormat.ASTC_8x5_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D10x5: return GalImageFormat.ASTC_10x5_UNORM_BLOCK;
|
||||||
|
case GalTextureFormat.Astc2D10x6: return GalImageFormat.ASTC_10x6_UNORM_BLOCK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalTextureType.Sint:
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.R32G32B32A32: return GalImageFormat.R32G32B32A32_SINT;
|
||||||
|
case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_SINT;
|
||||||
|
case GalTextureFormat.R32G32: return GalImageFormat.R32G32_SINT;
|
||||||
|
case GalTextureFormat.A8B8G8R8: return GalImageFormat.A8B8G8R8_SINT_PACK32;
|
||||||
|
case GalTextureFormat.A2B10G10R10: return GalImageFormat.A2B10G10R10_SINT_PACK32;
|
||||||
|
case GalTextureFormat.R32: return GalImageFormat.R32_SINT;
|
||||||
|
case GalTextureFormat.G8R8: return GalImageFormat.R8G8_SINT;
|
||||||
|
case GalTextureFormat.R16: return GalImageFormat.R16_SINT;
|
||||||
|
case GalTextureFormat.R8: return GalImageFormat.R8_SINT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalTextureType.Uint:
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.R32G32B32A32: return GalImageFormat.R32G32B32A32_UINT;
|
||||||
|
case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_UINT;
|
||||||
|
case GalTextureFormat.R32G32: return GalImageFormat.R32G32_UINT;
|
||||||
|
case GalTextureFormat.A8B8G8R8: return GalImageFormat.A8B8G8R8_UINT_PACK32;
|
||||||
|
case GalTextureFormat.A2B10G10R10: return GalImageFormat.A2B10G10R10_UINT_PACK32;
|
||||||
|
case GalTextureFormat.R32: return GalImageFormat.R32_UINT;
|
||||||
|
case GalTextureFormat.G8R8: return GalImageFormat.R8G8_UINT;
|
||||||
|
case GalTextureFormat.R16: return GalImageFormat.R16_UINT;
|
||||||
|
case GalTextureFormat.R8: return GalImageFormat.R8_UINT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalTextureType.Snorm_Force_Fp16:
|
||||||
|
//TODO
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalTextureType.Unorm_Force_Fp16:
|
||||||
|
//TODO
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GalTextureType.Float:
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.R32G32B32A32: return GalImageFormat.R32G32B32A32_SFLOAT;
|
||||||
|
case GalTextureFormat.R16G16B16A16: return GalImageFormat.R16G16B16A16_SFLOAT;
|
||||||
|
case GalTextureFormat.R32G32: return GalImageFormat.R32G32_SFLOAT;
|
||||||
|
case GalTextureFormat.R32: return GalImageFormat.R32_SFLOAT;
|
||||||
|
case GalTextureFormat.BC6H_SF16: return GalImageFormat.BC6H_SFLOAT_BLOCK;
|
||||||
|
case GalTextureFormat.BC6H_UF16: return GalImageFormat.BC6H_UFLOAT_BLOCK;
|
||||||
|
case GalTextureFormat.R16: return GalImageFormat.R16_SFLOAT;
|
||||||
|
case GalTextureFormat.BF10GF11RF11: return GalImageFormat.B10G11R11_UFLOAT_PACK32;
|
||||||
|
case GalTextureFormat.ZF32: return GalImageFormat.D32_SFLOAT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException("0x" + ((int)Format).ToString("x2") + " " + Type.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GalImageFormat ConvertFrameBuffer(GalFrameBufferFormat Format)
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalFrameBufferFormat.R32Float: return GalImageFormat.R32_SFLOAT;
|
||||||
|
case GalFrameBufferFormat.RGB10A2Unorm: return GalImageFormat.A2B10G10R10_UNORM_PACK32;
|
||||||
|
case GalFrameBufferFormat.RGBA8Srgb: return GalImageFormat.A8B8G8R8_SRGB_PACK32;
|
||||||
|
case GalFrameBufferFormat.RGBA16Float: return GalImageFormat.R16G16B16A16_SFLOAT;
|
||||||
|
case GalFrameBufferFormat.R16Float: return GalImageFormat.R16_SFLOAT;
|
||||||
|
case GalFrameBufferFormat.R8Unorm: return GalImageFormat.R8_UNORM;
|
||||||
|
case GalFrameBufferFormat.RGBA8Unorm: return GalImageFormat.A8B8G8R8_UNORM_PACK32;
|
||||||
|
case GalFrameBufferFormat.R11G11B10Float: return GalImageFormat.B10G11R11_UFLOAT_PACK32;
|
||||||
|
case GalFrameBufferFormat.RGBA32Float: return GalImageFormat.R32G32B32A32_SFLOAT;
|
||||||
|
case GalFrameBufferFormat.RG16Snorm: return GalImageFormat.R16G16_SNORM;
|
||||||
|
case GalFrameBufferFormat.RG16Float: return GalImageFormat.R16G16_SFLOAT;
|
||||||
|
case GalFrameBufferFormat.RG8Snorm: return GalImageFormat.R8_SNORM;
|
||||||
|
case GalFrameBufferFormat.RGBA8Snorm: return GalImageFormat.A8B8G8R8_SNORM_PACK32;
|
||||||
|
case GalFrameBufferFormat.RG8Unorm: return GalImageFormat.R8G8_UNORM;
|
||||||
|
case GalFrameBufferFormat.BGRA8Unorm: return GalImageFormat.A8B8G8R8_UNORM_PACK32;
|
||||||
|
case GalFrameBufferFormat.BGRA8Srgb: return GalImageFormat.A8B8G8R8_SRGB_PACK32;
|
||||||
|
case GalFrameBufferFormat.RG32Float: return GalImageFormat.R32G32_SFLOAT;
|
||||||
|
case GalFrameBufferFormat.RG32Sint: return GalImageFormat.R32G32_SINT;
|
||||||
|
case GalFrameBufferFormat.RG32Uint: return GalImageFormat.R32G32_UINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException(Format.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GalImageFormat ConvertZeta(GalZetaFormat Format)
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalZetaFormat.Z32Float: return GalImageFormat.D32_SFLOAT;
|
||||||
|
case GalZetaFormat.S8Z24Unorm: return GalImageFormat.D24_UNORM_S8_UINT;
|
||||||
|
case GalZetaFormat.Z16Unorm: return GalImageFormat.D16_UNORM;
|
||||||
|
case GalZetaFormat.Z32S8X24Float: return GalImageFormat.D32_SFLOAT_S8_UINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException(Format.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasColor(GalImageFormat Format)
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalImageFormat.R32G32B32A32_SFLOAT:
|
||||||
|
case GalImageFormat.R32G32B32A32_SINT:
|
||||||
|
case GalImageFormat.R32G32B32A32_UINT:
|
||||||
|
case GalImageFormat.R16G16B16A16_SFLOAT:
|
||||||
|
case GalImageFormat.R16G16B16A16_SINT:
|
||||||
|
case GalImageFormat.R16G16B16A16_UINT:
|
||||||
|
case GalImageFormat.R32G32_SFLOAT:
|
||||||
|
case GalImageFormat.R32G32_SINT:
|
||||||
|
case GalImageFormat.R32G32_UINT:
|
||||||
|
case GalImageFormat.A8B8G8R8_SNORM_PACK32:
|
||||||
|
case GalImageFormat.A8B8G8R8_UNORM_PACK32:
|
||||||
|
case GalImageFormat.A8B8G8R8_SINT_PACK32:
|
||||||
|
case GalImageFormat.A8B8G8R8_UINT_PACK32:
|
||||||
|
case GalImageFormat.A2B10G10R10_SINT_PACK32:
|
||||||
|
case GalImageFormat.A2B10G10R10_SNORM_PACK32:
|
||||||
|
case GalImageFormat.A2B10G10R10_UINT_PACK32:
|
||||||
|
case GalImageFormat.A2B10G10R10_UNORM_PACK32:
|
||||||
|
case GalImageFormat.R32_SFLOAT:
|
||||||
|
case GalImageFormat.R32_SINT:
|
||||||
|
case GalImageFormat.R32_UINT:
|
||||||
|
case GalImageFormat.BC6H_SFLOAT_BLOCK:
|
||||||
|
case GalImageFormat.BC6H_UFLOAT_BLOCK:
|
||||||
|
case GalImageFormat.A1R5G5B5_UNORM_PACK16:
|
||||||
|
case GalImageFormat.B5G6R5_UNORM_PACK16:
|
||||||
|
case GalImageFormat.BC7_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.R16G16_SFLOAT:
|
||||||
|
case GalImageFormat.R16G16_SINT:
|
||||||
|
case GalImageFormat.R16G16_SNORM:
|
||||||
|
case GalImageFormat.R16G16_UNORM:
|
||||||
|
case GalImageFormat.R8G8_SINT:
|
||||||
|
case GalImageFormat.R8G8_SNORM:
|
||||||
|
case GalImageFormat.R8G8_UINT:
|
||||||
|
case GalImageFormat.R8G8_UNORM:
|
||||||
|
case GalImageFormat.R16_SFLOAT:
|
||||||
|
case GalImageFormat.R16_SINT:
|
||||||
|
case GalImageFormat.R16_SNORM:
|
||||||
|
case GalImageFormat.R16_UINT:
|
||||||
|
case GalImageFormat.R16_UNORM:
|
||||||
|
case GalImageFormat.R8_SINT:
|
||||||
|
case GalImageFormat.R8_SNORM:
|
||||||
|
case GalImageFormat.R8_UINT:
|
||||||
|
case GalImageFormat.R8_UNORM:
|
||||||
|
case GalImageFormat.B10G11R11_UFLOAT_PACK32:
|
||||||
|
case GalImageFormat.BC1_RGBA_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.BC2_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.BC3_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.BC4_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.BC5_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_4x4_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_5x5_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_6x6_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_8x8_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_10x10_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_12x12_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_5x4_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_6x5_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_8x6_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_10x8_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_12x10_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_8x5_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_10x5_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_10x6_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.R4G4B4A4_UNORM_PACK16_REVERSED:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GalImageFormat.D24_UNORM_S8_UINT:
|
||||||
|
case GalImageFormat.D32_SFLOAT:
|
||||||
|
case GalImageFormat.D16_UNORM:
|
||||||
|
case GalImageFormat.D32_SFLOAT_S8_UINT:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException(Format.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasDepth(GalImageFormat Format)
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalImageFormat.D24_UNORM_S8_UINT:
|
||||||
|
case GalImageFormat.D32_SFLOAT:
|
||||||
|
case GalImageFormat.D16_UNORM:
|
||||||
|
case GalImageFormat.D32_SFLOAT_S8_UINT:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Depth formats are fewer than colors, so it's harder to miss one
|
||||||
|
//Instead of checking for individual formats, return false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasStencil(GalImageFormat Format)
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalImageFormat.D24_UNORM_S8_UINT:
|
||||||
|
case GalImageFormat.D32_SFLOAT_S8_UINT:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
124
Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs
Normal file
124
Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
class ImageHandler
|
||||||
|
{
|
||||||
|
//TODO: Use a variable value here
|
||||||
|
public const int MaxBpp = 16;
|
||||||
|
|
||||||
|
private static int CopyBuffer = 0;
|
||||||
|
private static int CopyBufferSize = 0;
|
||||||
|
|
||||||
|
public GalImage Image { get; private set; }
|
||||||
|
|
||||||
|
public int Width => Image.Width;
|
||||||
|
public int Height => Image.Height;
|
||||||
|
|
||||||
|
public GalImageFormat Format => Image.Format;
|
||||||
|
|
||||||
|
public PixelInternalFormat InternalFormat { get; private set; }
|
||||||
|
public PixelFormat PixelFormat { get; private set; }
|
||||||
|
public PixelType PixelType { get; private set; }
|
||||||
|
|
||||||
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
|
private bool Initialized;
|
||||||
|
|
||||||
|
public ImageHandler()
|
||||||
|
{
|
||||||
|
Handle = GL.GenTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageHandler(int Handle, GalImage Image)
|
||||||
|
{
|
||||||
|
this.Handle = Handle;
|
||||||
|
|
||||||
|
this.Image = Image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnsureSetup(GalImage Image)
|
||||||
|
{
|
||||||
|
if (Width != Image.Width ||
|
||||||
|
Height != Image.Height ||
|
||||||
|
Format != Image.Format ||
|
||||||
|
!Initialized)
|
||||||
|
{
|
||||||
|
(PixelInternalFormat InternalFormat, PixelFormat PixelFormat, PixelType PixelType) =
|
||||||
|
OGLEnumConverter.GetImageFormat(Image.Format);
|
||||||
|
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
|
||||||
|
if (Initialized)
|
||||||
|
{
|
||||||
|
if (CopyBuffer == 0)
|
||||||
|
{
|
||||||
|
CopyBuffer = GL.GenBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MaxWidth = Math.Max(Image.Width, Width);
|
||||||
|
int MaxHeight = Math.Max(Image.Height, Height);
|
||||||
|
|
||||||
|
int CurrentSize = MaxWidth * MaxHeight * MaxBpp;
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyBuffer);
|
||||||
|
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyBuffer);
|
||||||
|
|
||||||
|
if (CopyBufferSize < CurrentSize)
|
||||||
|
{
|
||||||
|
CopyBufferSize = CurrentSize;
|
||||||
|
|
||||||
|
GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero);
|
||||||
|
|
||||||
|
GL.DeleteTexture(Handle);
|
||||||
|
|
||||||
|
Handle = GL.GenTexture();
|
||||||
|
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int MinFilter = (int)TextureMinFilter.Linear;
|
||||||
|
const int MagFilter = (int)TextureMagFilter.Linear;
|
||||||
|
|
||||||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
|
||||||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
|
||||||
|
|
||||||
|
const int Level = 0;
|
||||||
|
const int Border = 0;
|
||||||
|
|
||||||
|
GL.TexImage2D(
|
||||||
|
TextureTarget.Texture2D,
|
||||||
|
Level,
|
||||||
|
InternalFormat,
|
||||||
|
Image.Width,
|
||||||
|
Image.Height,
|
||||||
|
Border,
|
||||||
|
PixelFormat,
|
||||||
|
PixelType,
|
||||||
|
IntPtr.Zero);
|
||||||
|
|
||||||
|
if (Initialized)
|
||||||
|
{
|
||||||
|
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
|
||||||
|
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Image = Image;
|
||||||
|
|
||||||
|
this.InternalFormat = InternalFormat;
|
||||||
|
this.PixelFormat = PixelFormat;
|
||||||
|
this.PixelType = PixelType;
|
||||||
|
|
||||||
|
Initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasColor { get => ImageFormatConverter.HasColor(Format); }
|
||||||
|
public bool HasDepth { get => ImageFormatConverter.HasDepth(Format); }
|
||||||
|
public bool HasStencil { get => ImageFormatConverter.HasStencil(Format); }
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,13 +36,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public void SetData(long Key, long Size, IntPtr HostAddress)
|
public void SetData(long Key, long Size, IntPtr HostAddress)
|
||||||
{
|
{
|
||||||
if (!Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
|
if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer.SetData(Size, HostAddress);
|
Buffer.SetData(Size, HostAddress);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryGetUbo(long Key, out int UboHandle)
|
public bool TryGetUbo(long Key, out int UboHandle)
|
||||||
{
|
{
|
||||||
|
|
|
@ -125,40 +125,75 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
throw new ArgumentException(nameof(Type));
|
throw new ArgumentException(nameof(Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (PixelFormat, PixelType) GetTextureFormat(GalTextureFormat Format)
|
public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat Format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (Format)
|
||||||
{
|
{
|
||||||
case GalTextureFormat.R32G32B32A32: return (PixelFormat.Rgba, PixelType.Float);
|
case GalImageFormat.R32G32B32A32_SFLOAT: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float);
|
||||||
case GalTextureFormat.R16G16B16A16: return (PixelFormat.Rgba, PixelType.HalfFloat);
|
case GalImageFormat.R32G32B32A32_SINT: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int);
|
||||||
case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte);
|
case GalImageFormat.R32G32B32A32_UINT: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt);
|
||||||
case GalTextureFormat.A2B10G10R10: return (PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
|
case GalImageFormat.R16G16B16A16_SFLOAT: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat);
|
||||||
case GalTextureFormat.R32: return (PixelFormat.Red, PixelType.Float);
|
case GalImageFormat.R16G16B16A16_SINT: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short);
|
||||||
case GalTextureFormat.A1B5G5R5: return (PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
case GalImageFormat.R16G16B16A16_UINT: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort);
|
||||||
case GalTextureFormat.B5G6R5: return (PixelFormat.Rgb, PixelType.UnsignedShort565);
|
case GalImageFormat.R32G32_SFLOAT: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float);
|
||||||
case GalTextureFormat.G8R8: return (PixelFormat.Rg, PixelType.UnsignedByte);
|
case GalImageFormat.R32G32_SINT: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int);
|
||||||
case GalTextureFormat.R16: return (PixelFormat.Red, PixelType.HalfFloat);
|
case GalImageFormat.R32G32_UINT: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt);
|
||||||
case GalTextureFormat.R8: return (PixelFormat.Red, PixelType.UnsignedByte);
|
case GalImageFormat.A8B8G8R8_SNORM_PACK32: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte);
|
||||||
case GalTextureFormat.ZF32: return (PixelFormat.DepthComponent, PixelType.Float);
|
case GalImageFormat.A8B8G8R8_UNORM_PACK32: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||||
case GalTextureFormat.BF10GF11RF11: return (PixelFormat.Rgb, PixelType.UnsignedInt10F11F11FRev);
|
case GalImageFormat.A8B8G8R8_SINT_PACK32: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte);
|
||||||
case GalTextureFormat.Z24S8: return (PixelFormat.DepthStencil, PixelType.UnsignedInt248);
|
case GalImageFormat.A8B8G8R8_UINT_PACK32: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte);
|
||||||
|
case GalImageFormat.A8B8G8R8_SRGB_PACK32: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||||
|
case GalImageFormat.A2B10G10R10_UINT_PACK32: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed);
|
||||||
|
case GalImageFormat.A2B10G10R10_UNORM_PACK32: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
|
||||||
|
case GalImageFormat.R32_SFLOAT: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
|
||||||
|
case GalImageFormat.R32_SINT: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
|
||||||
|
case GalImageFormat.R32_UINT: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
|
||||||
|
case GalImageFormat.A1R5G5B5_UNORM_PACK16: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
||||||
|
case GalImageFormat.B5G6R5_UNORM_PACK16: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565);
|
||||||
|
case GalImageFormat.R16G16_SFLOAT: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
|
||||||
|
case GalImageFormat.R16G16_SINT: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
|
||||||
|
case GalImageFormat.R16G16_SNORM: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte);
|
||||||
|
case GalImageFormat.R16G16_UNORM: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort);
|
||||||
|
case GalImageFormat.R8G8_SINT: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte);
|
||||||
|
case GalImageFormat.R8G8_SNORM: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte);
|
||||||
|
case GalImageFormat.R8G8_UINT: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte);
|
||||||
|
case GalImageFormat.R8G8_UNORM: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte);
|
||||||
|
case GalImageFormat.R16_SFLOAT: return (PixelInternalFormat.R16f, PixelFormat.Red, PixelType.HalfFloat);
|
||||||
|
case GalImageFormat.R16_SINT: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, PixelType.Short);
|
||||||
|
case GalImageFormat.R16_SNORM: return (PixelInternalFormat.R16Snorm, PixelFormat.Red, PixelType.Byte);
|
||||||
|
case GalImageFormat.R16_UINT: return (PixelInternalFormat.R16ui, PixelFormat.RedInteger, PixelType.UnsignedShort);
|
||||||
|
case GalImageFormat.R16_UNORM: return (PixelInternalFormat.R16, PixelFormat.Red, PixelType.UnsignedShort);
|
||||||
|
case GalImageFormat.R8_SINT: return (PixelInternalFormat.R8i, PixelFormat.RedInteger, PixelType.Byte);
|
||||||
|
case GalImageFormat.R8_SNORM: return (PixelInternalFormat.R8Snorm, PixelFormat.Red, PixelType.Byte);
|
||||||
|
case GalImageFormat.R8_UINT: return (PixelInternalFormat.R8ui, PixelFormat.RedInteger, PixelType.UnsignedByte);
|
||||||
|
case GalImageFormat.R8_UNORM: return (PixelInternalFormat.R8, PixelFormat.Red, PixelType.UnsignedByte);
|
||||||
|
case GalImageFormat.B10G11R11_UFLOAT_PACK32: return (PixelInternalFormat.R11fG11fB10f, PixelFormat.Rgb, PixelType.UnsignedInt10F11F11FRev);
|
||||||
|
|
||||||
|
case GalImageFormat.R4G4B4A4_UNORM_PACK16_REVERSED: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed);
|
||||||
|
|
||||||
|
case GalImageFormat.D24_UNORM_S8_UINT: return (PixelInternalFormat.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248);
|
||||||
|
case GalImageFormat.D32_SFLOAT: return (PixelInternalFormat.DepthComponent32f, PixelFormat.DepthComponent, PixelType.Float);
|
||||||
|
case GalImageFormat.D16_UNORM: return (PixelInternalFormat.DepthComponent16, PixelFormat.DepthComponent, PixelType.UnsignedShort);
|
||||||
|
case GalImageFormat.D32_SFLOAT_S8_UINT: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(Format.ToString());
|
throw new NotImplementedException(Format.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InternalFormat GetCompressedTextureFormat(GalTextureFormat Format)
|
public static InternalFormat GetCompressedImageFormat(GalImageFormat Format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (Format)
|
||||||
{
|
{
|
||||||
case GalTextureFormat.BC6H_UF16: return InternalFormat.CompressedRgbBptcUnsignedFloat;
|
case GalImageFormat.BC6H_UFLOAT_BLOCK: return InternalFormat.CompressedRgbBptcUnsignedFloat;
|
||||||
case GalTextureFormat.BC6H_SF16: return InternalFormat.CompressedRgbBptcSignedFloat;
|
case GalImageFormat.BC6H_SFLOAT_BLOCK: return InternalFormat.CompressedRgbBptcSignedFloat;
|
||||||
case GalTextureFormat.BC7U: return InternalFormat.CompressedRgbaBptcUnorm;
|
case GalImageFormat.BC7_UNORM_BLOCK: return InternalFormat.CompressedRgbaBptcUnorm;
|
||||||
case GalTextureFormat.BC1: return InternalFormat.CompressedRgbaS3tcDxt1Ext;
|
case GalImageFormat.BC1_RGBA_UNORM_BLOCK: return InternalFormat.CompressedRgbaS3tcDxt1Ext;
|
||||||
case GalTextureFormat.BC2: return InternalFormat.CompressedRgbaS3tcDxt3Ext;
|
case GalImageFormat.BC2_UNORM_BLOCK: return InternalFormat.CompressedRgbaS3tcDxt3Ext;
|
||||||
case GalTextureFormat.BC3: return InternalFormat.CompressedRgbaS3tcDxt5Ext;
|
case GalImageFormat.BC3_UNORM_BLOCK: return InternalFormat.CompressedRgbaS3tcDxt5Ext;
|
||||||
case GalTextureFormat.BC4: return InternalFormat.CompressedRedRgtc1;
|
case GalImageFormat.BC4_SNORM_BLOCK: return InternalFormat.CompressedSignedRedRgtc1;
|
||||||
case GalTextureFormat.BC5: return InternalFormat.CompressedRgRgtc2;
|
case GalImageFormat.BC4_UNORM_BLOCK: return InternalFormat.CompressedRedRgtc1;
|
||||||
|
case GalImageFormat.BC5_SNORM_BLOCK: return InternalFormat.CompressedSignedRgRgtc2;
|
||||||
|
case GalImageFormat.BC5_UNORM_BLOCK: return InternalFormat.CompressedRgRgtc2;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(Format.ToString());
|
throw new NotImplementedException(Format.ToString());
|
||||||
|
@ -189,12 +224,27 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalTextureWrap.ClampToEdge: return TextureWrapMode.ClampToEdge;
|
case GalTextureWrap.ClampToEdge: return TextureWrapMode.ClampToEdge;
|
||||||
case GalTextureWrap.ClampToBorder: return TextureWrapMode.ClampToBorder;
|
case GalTextureWrap.ClampToBorder: return TextureWrapMode.ClampToBorder;
|
||||||
case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
|
case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: Those needs extensions (and are currently wrong).
|
if (OGLExtension.HasTextureMirrorClamp())
|
||||||
|
{
|
||||||
|
switch (Wrap)
|
||||||
|
{
|
||||||
|
case GalTextureWrap.MirrorClampToEdge: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToEdgeExt;
|
||||||
|
case GalTextureWrap.MirrorClampToBorder: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToBorderExt;
|
||||||
|
case GalTextureWrap.MirrorClamp: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampExt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Fallback to non-mirrored clamps
|
||||||
|
switch (Wrap)
|
||||||
|
{
|
||||||
case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
|
case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
|
||||||
case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder;
|
case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder;
|
||||||
case GalTextureWrap.MirrorClamp: return TextureWrapMode.Clamp;
|
case GalTextureWrap.MirrorClamp: return TextureWrapMode.Clamp;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Wrap));
|
throw new ArgumentException(nameof(Wrap));
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private static bool EnhancedLayouts;
|
private static bool EnhancedLayouts;
|
||||||
|
|
||||||
|
private static bool TextureMirrorClamp;
|
||||||
|
|
||||||
public static bool HasEnhancedLayouts()
|
public static bool HasEnhancedLayouts()
|
||||||
{
|
{
|
||||||
EnsureInitialized();
|
EnsureInitialized();
|
||||||
|
@ -15,6 +17,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return EnhancedLayouts;
|
return EnhancedLayouts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool HasTextureMirrorClamp()
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
|
||||||
|
return TextureMirrorClamp;
|
||||||
|
}
|
||||||
|
|
||||||
private static void EnsureInitialized()
|
private static void EnsureInitialized()
|
||||||
{
|
{
|
||||||
if (Initialized)
|
if (Initialized)
|
||||||
|
@ -23,6 +32,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
|
|
||||||
EnhancedLayouts = HasExtension("GL_ARB_enhanced_layouts");
|
EnhancedLayouts = HasExtension("GL_ARB_enhanced_layouts");
|
||||||
|
|
||||||
|
TextureMirrorClamp = HasExtension("GL_EXT_texture_mirror_clamp");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool HasExtension(string Name)
|
private static bool HasExtension(string Name)
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public class OGLFrameBuffer : IGalFrameBuffer
|
class OGLFrameBuffer : IGalFrameBuffer
|
||||||
{
|
{
|
||||||
private struct Rect
|
private struct Rect
|
||||||
{
|
{
|
||||||
|
@ -22,43 +21,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FrameBuffer
|
|
||||||
{
|
|
||||||
public int Width { get; set; }
|
|
||||||
public int Height { get; set; }
|
|
||||||
|
|
||||||
public int Handle { get; private set; }
|
|
||||||
public int RbHandle { get; private set; }
|
|
||||||
public int TexHandle { get; private set; }
|
|
||||||
|
|
||||||
public FrameBuffer(int Width, int Height, bool HasRenderBuffer)
|
|
||||||
{
|
|
||||||
this.Width = Width;
|
|
||||||
this.Height = Height;
|
|
||||||
|
|
||||||
Handle = GL.GenFramebuffer();
|
|
||||||
TexHandle = GL.GenTexture();
|
|
||||||
|
|
||||||
if (HasRenderBuffer)
|
|
||||||
{
|
|
||||||
RbHandle = GL.GenRenderbuffer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private const int NativeWidth = 1280;
|
private const int NativeWidth = 1280;
|
||||||
private const int NativeHeight = 720;
|
private const int NativeHeight = 720;
|
||||||
|
|
||||||
private Dictionary<long, FrameBuffer> Fbs;
|
private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8_UNORM_PACK32;
|
||||||
|
|
||||||
|
private OGLTexture Texture;
|
||||||
|
|
||||||
|
private ImageHandler RawTex;
|
||||||
|
private ImageHandler ReadTex;
|
||||||
|
|
||||||
private Rect Viewport;
|
private Rect Viewport;
|
||||||
private Rect Window;
|
private Rect Window;
|
||||||
|
|
||||||
private FrameBuffer CurrFb;
|
|
||||||
private FrameBuffer CurrReadFb;
|
|
||||||
|
|
||||||
private FrameBuffer RawFb;
|
|
||||||
|
|
||||||
private bool FlipX;
|
private bool FlipX;
|
||||||
private bool FlipY;
|
private bool FlipY;
|
||||||
|
|
||||||
|
@ -67,111 +42,163 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
private int CropRight;
|
private int CropRight;
|
||||||
private int CropBottom;
|
private int CropBottom;
|
||||||
|
|
||||||
public OGLFrameBuffer()
|
//This framebuffer is used to attach guest rendertargets,
|
||||||
|
//think of it as a dummy OpenGL VAO
|
||||||
|
private int DummyFrameBuffer;
|
||||||
|
|
||||||
|
//These framebuffers are used to blit images
|
||||||
|
private int SrcFb;
|
||||||
|
private int DstFb;
|
||||||
|
|
||||||
|
//Holds current attachments, used to avoid unnecesary calls to OpenGL
|
||||||
|
private int[] ColorAttachments;
|
||||||
|
|
||||||
|
private int DepthAttachment;
|
||||||
|
private int StencilAttachment;
|
||||||
|
|
||||||
|
public OGLFrameBuffer(OGLTexture Texture)
|
||||||
{
|
{
|
||||||
Fbs = new Dictionary<long, FrameBuffer>();
|
ColorAttachments = new int[8];
|
||||||
|
|
||||||
|
this.Texture = Texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create(long Key, int Width, int Height)
|
public void BindColor(long Key, int Attachment)
|
||||||
{
|
{
|
||||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||||
{
|
{
|
||||||
if (Fb.Width != Width ||
|
EnsureFrameBuffer();
|
||||||
Fb.Height != Height)
|
|
||||||
{
|
|
||||||
SetupTexture(Fb.TexHandle, Width, Height);
|
|
||||||
|
|
||||||
Fb.Width = Width;
|
Attach(ref ColorAttachments[Attachment], Tex.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||||
Fb.Height = Height;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UnbindColor(Attachment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
public void UnbindColor(int Attachment)
|
||||||
|
{
|
||||||
|
EnsureFrameBuffer();
|
||||||
|
|
||||||
|
Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fb = new FrameBuffer(Width, Height, true);
|
public void BindZeta(long Key)
|
||||||
|
{
|
||||||
SetupTexture(Fb.TexHandle, Width, Height);
|
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||||
|
{
|
||||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
EnsureFrameBuffer();
|
||||||
|
|
||||||
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fb.RbHandle);
|
|
||||||
|
|
||||||
GL.RenderbufferStorage(
|
|
||||||
RenderbufferTarget.Renderbuffer,
|
|
||||||
RenderbufferStorage.Depth24Stencil8,
|
|
||||||
Width,
|
|
||||||
Height);
|
|
||||||
|
|
||||||
GL.FramebufferRenderbuffer(
|
|
||||||
FramebufferTarget.Framebuffer,
|
|
||||||
FramebufferAttachment.DepthStencilAttachment,
|
|
||||||
RenderbufferTarget.Renderbuffer,
|
|
||||||
Fb.RbHandle);
|
|
||||||
|
|
||||||
|
if (Tex.HasDepth && Tex.HasStencil)
|
||||||
|
{
|
||||||
|
if (DepthAttachment != Tex.Handle ||
|
||||||
|
StencilAttachment != Tex.Handle)
|
||||||
|
{
|
||||||
GL.FramebufferTexture(
|
GL.FramebufferTexture(
|
||||||
FramebufferTarget.Framebuffer,
|
FramebufferTarget.DrawFramebuffer,
|
||||||
FramebufferAttachment.ColorAttachment0,
|
FramebufferAttachment.DepthStencilAttachment,
|
||||||
Fb.TexHandle,
|
Tex.Handle,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
DepthAttachment = Tex.Handle;
|
||||||
|
|
||||||
Fbs.Add(Key, Fb);
|
StencilAttachment = Tex.Handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Tex.HasDepth)
|
||||||
|
{
|
||||||
|
Attach(ref DepthAttachment, Tex.Handle, FramebufferAttachment.DepthAttachment);
|
||||||
|
|
||||||
|
Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
|
||||||
|
}
|
||||||
|
else if (Tex.HasStencil)
|
||||||
|
{
|
||||||
|
Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
|
||||||
|
|
||||||
|
Attach(ref StencilAttachment, Tex.Handle, FramebufferAttachment.StencilAttachment);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UnbindZeta();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind(long Key)
|
public void UnbindZeta()
|
||||||
{
|
{
|
||||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
EnsureFrameBuffer();
|
||||||
{
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle);
|
|
||||||
|
|
||||||
CurrFb = Fb;
|
if (DepthAttachment != 0 ||
|
||||||
|
StencilAttachment != 0)
|
||||||
|
{
|
||||||
|
GL.FramebufferTexture(
|
||||||
|
FramebufferTarget.DrawFramebuffer,
|
||||||
|
FramebufferAttachment.DepthStencilAttachment,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
|
||||||
|
DepthAttachment = 0;
|
||||||
|
|
||||||
|
StencilAttachment = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BindTexture(long Key, int Index)
|
public void BindTexture(long Key, int Index)
|
||||||
{
|
{
|
||||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||||
{
|
{
|
||||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
|
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(long Key)
|
public void Set(long Key)
|
||||||
{
|
{
|
||||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||||
{
|
{
|
||||||
CurrReadFb = Fb;
|
ReadTex = Tex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(byte[] Data, int Width, int Height)
|
public void Set(byte[] Data, int Width, int Height)
|
||||||
{
|
{
|
||||||
if (RawFb == null)
|
if (RawTex == null)
|
||||||
{
|
{
|
||||||
CreateRawFb(Width, Height);
|
RawTex = new ImageHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RawFb.Width != Width ||
|
RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat));
|
||||||
RawFb.Height != Height)
|
|
||||||
{
|
|
||||||
SetupTexture(RawFb.TexHandle, Width, Height);
|
|
||||||
|
|
||||||
RawFb.Width = Width;
|
GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle);
|
||||||
RawFb.Height = Height;
|
|
||||||
|
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, RawTex.PixelFormat, RawTex.PixelType, Data);
|
||||||
|
|
||||||
|
ReadTex = RawTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
public void SetMap(int[] Map)
|
||||||
|
{
|
||||||
|
if (Map != null && Map.Length > 0)
|
||||||
|
{
|
||||||
|
DrawBuffersEnum[] Mode = new DrawBuffersEnum[Map.Length];
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, RawFb.TexHandle);
|
for (int i = 0; i < Map.Length; i++)
|
||||||
|
{
|
||||||
|
Mode[i] = DrawBuffersEnum.ColorAttachment0 + Map[i];
|
||||||
|
}
|
||||||
|
|
||||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
GL.DrawBuffers(Mode.Length, Mode);
|
||||||
|
}
|
||||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, Format, Type, Data);
|
else
|
||||||
|
{
|
||||||
CurrReadFb = RawFb;
|
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
|
public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
|
||||||
|
@ -208,14 +235,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public void Render()
|
public void Render()
|
||||||
{
|
{
|
||||||
if (CurrReadFb != null)
|
if (ReadTex == null)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int SrcX0, SrcX1, SrcY0, SrcY1;
|
int SrcX0, SrcX1, SrcY0, SrcY1;
|
||||||
|
|
||||||
if (CropLeft == 0 && CropRight == 0)
|
if (CropLeft == 0 && CropRight == 0)
|
||||||
{
|
{
|
||||||
SrcX0 = 0;
|
SrcX0 = 0;
|
||||||
SrcX1 = CurrReadFb.Width;
|
SrcX1 = ReadTex.Width;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -226,7 +256,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
if (CropTop == 0 && CropBottom == 0)
|
if (CropTop == 0 && CropBottom == 0)
|
||||||
{
|
{
|
||||||
SrcY0 = 0;
|
SrcY0 = 0;
|
||||||
SrcY1 = CurrReadFb.Height;
|
SrcY1 = ReadTex.Height;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -249,19 +279,27 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
|
||||||
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
||||||
|
|
||||||
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
||||||
|
|
||||||
GL.Viewport(0, 0, Window.Width, Window.Height);
|
GL.Viewport(0, 0, Window.Width, Window.Height);
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrReadFb.Handle);
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||||
|
|
||||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
|
||||||
|
|
||||||
|
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
||||||
|
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||||
|
|
||||||
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||||
|
|
||||||
GL.BlitFramebuffer(
|
GL.BlitFramebuffer(
|
||||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||||
DstX0, DstY0, DstX1, DstY1,
|
DstX0, DstY0, DstX1, DstY1,
|
||||||
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
|
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
|
||||||
}
|
|
||||||
|
EnsureFrameBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Copy(
|
public void Copy(
|
||||||
|
@ -276,39 +314,80 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
int DstX1,
|
int DstX1,
|
||||||
int DstY1)
|
int DstY1)
|
||||||
{
|
{
|
||||||
if (Fbs.TryGetValue(SrcKey, out FrameBuffer SrcFb) &&
|
if (Texture.TryGetImage(SrcKey, out ImageHandler SrcTex) &&
|
||||||
Fbs.TryGetValue(DstKey, out FrameBuffer DstFb))
|
Texture.TryGetImage(DstKey, out ImageHandler DstTex))
|
||||||
{
|
{
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb.Handle);
|
if (SrcTex.HasColor != DstTex.HasColor ||
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb.Handle);
|
SrcTex.HasDepth != DstTex.HasDepth ||
|
||||||
|
SrcTex.HasStencil != DstTex.HasStencil)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
if (SrcTex.HasColor)
|
||||||
|
{
|
||||||
GL.BlitFramebuffer(
|
CopyTextures(
|
||||||
SrcX0, SrcY0, SrcX1, SrcY1,
|
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||||
DstX0, DstY0, DstX1, DstY1,
|
DstX0, DstY0, DstX1, DstY1,
|
||||||
|
SrcTex.Handle,
|
||||||
|
DstTex.Handle,
|
||||||
|
FramebufferAttachment.ColorAttachment0,
|
||||||
ClearBufferMask.ColorBufferBit,
|
ClearBufferMask.ColorBufferBit,
|
||||||
BlitFramebufferFilter.Linear);
|
true);
|
||||||
|
}
|
||||||
|
else if (SrcTex.HasDepth && SrcTex.HasStencil)
|
||||||
|
{
|
||||||
|
CopyTextures(
|
||||||
|
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||||
|
DstX0, DstY0, DstX1, DstY1,
|
||||||
|
SrcTex.Handle,
|
||||||
|
DstTex.Handle,
|
||||||
|
FramebufferAttachment.DepthStencilAttachment,
|
||||||
|
ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
else if (SrcTex.HasDepth)
|
||||||
|
{
|
||||||
|
CopyTextures(
|
||||||
|
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||||
|
DstX0, DstY0, DstX1, DstY1,
|
||||||
|
SrcTex.Handle,
|
||||||
|
DstTex.Handle,
|
||||||
|
FramebufferAttachment.DepthAttachment,
|
||||||
|
ClearBufferMask.DepthBufferBit,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
else if (SrcTex.HasStencil)
|
||||||
|
{
|
||||||
|
CopyTextures(
|
||||||
|
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||||
|
DstX0, DstY0, DstX1, DstY1,
|
||||||
|
SrcTex.Handle,
|
||||||
|
DstTex.Handle,
|
||||||
|
FramebufferAttachment.StencilAttachment,
|
||||||
|
ClearBufferMask.StencilBufferBit,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void GetBufferData(long Key, Action<byte[]> Callback)
|
public void GetBufferData(long Key, Action<byte[]> Callback)
|
||||||
{
|
{
|
||||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||||
{
|
{
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle);
|
byte[] Data = new byte[Tex.Width * Tex.Height * ImageHandler.MaxBpp];
|
||||||
|
|
||||||
byte[] Data = new byte[Fb.Width * Fb.Height * 4];
|
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||||
|
|
||||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
GL.GetTexImage(
|
||||||
|
TextureTarget.Texture2D,
|
||||||
GL.ReadPixels(
|
|
||||||
0,
|
0,
|
||||||
0,
|
Tex.PixelFormat,
|
||||||
Fb.Width,
|
Tex.PixelType,
|
||||||
Fb.Height,
|
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
Data);
|
Data);
|
||||||
|
|
||||||
Callback(Data);
|
Callback(Data);
|
||||||
|
@ -319,83 +398,99 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
long Key,
|
long Key,
|
||||||
int Width,
|
int Width,
|
||||||
int Height,
|
int Height,
|
||||||
GalTextureFormat Format,
|
|
||||||
byte[] Buffer)
|
byte[] Buffer)
|
||||||
{
|
{
|
||||||
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
if (Texture.TryGetImage(Key, out ImageHandler Tex))
|
||||||
{
|
{
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Fb.TexHandle);
|
GL.BindTexture(TextureTarget.Texture2D, Tex.Handle);
|
||||||
|
|
||||||
const int Level = 0;
|
const int Level = 0;
|
||||||
const int Border = 0;
|
const int Border = 0;
|
||||||
|
|
||||||
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
|
||||||
|
|
||||||
(PixelFormat GlFormat, PixelType Type) = OGLEnumConverter.GetTextureFormat(Format);
|
|
||||||
|
|
||||||
GL.TexImage2D(
|
GL.TexImage2D(
|
||||||
TextureTarget.Texture2D,
|
TextureTarget.Texture2D,
|
||||||
Level,
|
Level,
|
||||||
InternalFmt,
|
Tex.InternalFormat,
|
||||||
Width,
|
Width,
|
||||||
Height,
|
Height,
|
||||||
Border,
|
Border,
|
||||||
GlFormat,
|
Tex.PixelFormat,
|
||||||
Type,
|
Tex.PixelType,
|
||||||
Buffer);
|
Buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateRawFb(int Width, int Height)
|
private void EnsureFrameBuffer()
|
||||||
{
|
{
|
||||||
if (RawFb == null)
|
if (DummyFrameBuffer == 0)
|
||||||
{
|
{
|
||||||
RawFb = new FrameBuffer(Width, Height, false);
|
DummyFrameBuffer = GL.GenFramebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
SetupTexture(RawFb.TexHandle, Width, Height);
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
||||||
|
}
|
||||||
RawFb.Width = Width;
|
|
||||||
RawFb.Height = Height;
|
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, RawFb.Handle);
|
|
||||||
|
|
||||||
|
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
|
||||||
|
{
|
||||||
|
if (OldHandle != NewHandle)
|
||||||
|
{
|
||||||
GL.FramebufferTexture(
|
GL.FramebufferTexture(
|
||||||
FramebufferTarget.Framebuffer,
|
FramebufferTarget.DrawFramebuffer,
|
||||||
FramebufferAttachment.ColorAttachment0,
|
FbAttachment,
|
||||||
RawFb.TexHandle,
|
NewHandle,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
GL.Viewport(0, 0, Width, Height);
|
OldHandle = NewHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupTexture(int Handle, int Width, int Height)
|
private void CopyTextures(
|
||||||
|
int SrcX0,
|
||||||
|
int SrcY0,
|
||||||
|
int SrcX1,
|
||||||
|
int SrcY1,
|
||||||
|
int DstX0,
|
||||||
|
int DstY0,
|
||||||
|
int DstX1,
|
||||||
|
int DstY1,
|
||||||
|
int SrcTexture,
|
||||||
|
int DstTexture,
|
||||||
|
FramebufferAttachment Attachment,
|
||||||
|
ClearBufferMask Mask,
|
||||||
|
bool Color)
|
||||||
{
|
{
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
if (SrcFb == 0) SrcFb = GL.GenFramebuffer();
|
||||||
|
if (DstFb == 0) DstFb = GL.GenFramebuffer();
|
||||||
|
|
||||||
const int MinFilter = (int)TextureMinFilter.Linear;
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
|
||||||
const int MagFilter = (int)TextureMagFilter.Linear;
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
|
||||||
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
|
GL.FramebufferTexture(
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
|
FramebufferTarget.ReadFramebuffer,
|
||||||
|
Attachment,
|
||||||
|
SrcTexture,
|
||||||
|
0);
|
||||||
|
|
||||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8);
|
GL.FramebufferTexture(
|
||||||
|
FramebufferTarget.DrawFramebuffer,
|
||||||
|
Attachment,
|
||||||
|
DstTexture,
|
||||||
|
0);
|
||||||
|
|
||||||
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
if (Color)
|
||||||
|
{
|
||||||
|
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||||
|
}
|
||||||
|
|
||||||
const int Level = 0;
|
GL.Clear(Mask);
|
||||||
const int Border = 0;
|
|
||||||
|
|
||||||
GL.TexImage2D(
|
GL.BlitFramebuffer(
|
||||||
TextureTarget.Texture2D,
|
SrcX0, SrcY0, SrcX1, SrcY1,
|
||||||
Level,
|
DstX0, DstY0, DstX1, DstY1,
|
||||||
InternalFmt,
|
Mask,
|
||||||
Width,
|
Color ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest);
|
||||||
Height,
|
|
||||||
Border,
|
EnsureFrameBuffer();
|
||||||
Format,
|
|
||||||
Type,
|
|
||||||
IntPtr.Zero);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{ GalVertexAttribSize._11_11_10, 3 }
|
{ GalVertexAttribSize._11_11_10, 3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> AttribTypes =
|
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> SignedAttribTypes =
|
||||||
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||||
{
|
{
|
||||||
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
|
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
|
||||||
|
@ -40,8 +40,26 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{ GalVertexAttribSize._8_8, VertexAttribPointerType.Byte },
|
{ GalVertexAttribSize._8_8, VertexAttribPointerType.Byte },
|
||||||
{ GalVertexAttribSize._16, VertexAttribPointerType.Short },
|
{ GalVertexAttribSize._16, VertexAttribPointerType.Short },
|
||||||
{ GalVertexAttribSize._8, VertexAttribPointerType.Byte },
|
{ GalVertexAttribSize._8, VertexAttribPointerType.Byte },
|
||||||
{ GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int }, //?
|
{ GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int2101010Rev }
|
||||||
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.Int } //?
|
};
|
||||||
|
|
||||||
|
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> UnsignedAttribTypes =
|
||||||
|
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||||
|
{
|
||||||
|
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.UnsignedInt },
|
||||||
|
{ GalVertexAttribSize._32_32_32, VertexAttribPointerType.UnsignedInt },
|
||||||
|
{ GalVertexAttribSize._16_16_16_16, VertexAttribPointerType.UnsignedShort },
|
||||||
|
{ GalVertexAttribSize._32_32, VertexAttribPointerType.UnsignedInt },
|
||||||
|
{ GalVertexAttribSize._16_16_16, VertexAttribPointerType.UnsignedShort },
|
||||||
|
{ GalVertexAttribSize._8_8_8_8, VertexAttribPointerType.UnsignedByte },
|
||||||
|
{ GalVertexAttribSize._16_16, VertexAttribPointerType.UnsignedShort },
|
||||||
|
{ GalVertexAttribSize._32, VertexAttribPointerType.UnsignedInt },
|
||||||
|
{ GalVertexAttribSize._8_8_8, VertexAttribPointerType.UnsignedByte },
|
||||||
|
{ GalVertexAttribSize._8_8, VertexAttribPointerType.UnsignedByte },
|
||||||
|
{ GalVertexAttribSize._16, VertexAttribPointerType.UnsignedShort },
|
||||||
|
{ GalVertexAttribSize._8, VertexAttribPointerType.UnsignedByte },
|
||||||
|
{ GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.UnsignedInt2101010Rev },
|
||||||
|
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.UnsignedInt10F11F11FRev }
|
||||||
};
|
};
|
||||||
|
|
||||||
private GalPipelineState Old;
|
private GalPipelineState Old;
|
||||||
|
@ -108,9 +126,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
BindVertexLayout(New);
|
BindVertexLayout(New);
|
||||||
|
|
||||||
if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY)
|
if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance)
|
||||||
{
|
{
|
||||||
Shader.SetFlip(New.FlipX, New.FlipY);
|
Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
||||||
|
@ -272,8 +290,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private void BindConstBuffers(GalPipelineState New)
|
private void BindConstBuffers(GalPipelineState New)
|
||||||
{
|
{
|
||||||
//Index 0 is reserved
|
int FreeBinding = OGLShader.ReservedCbufCount;
|
||||||
int FreeBinding = 1;
|
|
||||||
|
|
||||||
void BindIfNotNull(OGLShaderStage Stage)
|
void BindIfNotNull(OGLShaderStage Stage)
|
||||||
{
|
{
|
||||||
|
@ -341,7 +358,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Type = AttribTypes[Attrib.Size] + (Unsigned ? 1 : 0);
|
if (Unsigned)
|
||||||
|
{
|
||||||
|
Type = UnsignedAttribTypes[Attrib.Size];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Type = SignedAttribTypes[Attrib.Size];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Size = AttribElements[Attrib.Size];
|
int Size = AttribElements[Attrib.Size];
|
||||||
|
@ -360,6 +384,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
|
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Binding.Instanced && Binding.Divisor != 0)
|
||||||
|
{
|
||||||
|
GL.VertexAttribDivisor(Attrib.Index, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.VertexAttribDivisor(Attrib.Index, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public class OGLRasterizer : IGalRasterizer
|
class OGLRasterizer : IGalRasterizer
|
||||||
{
|
{
|
||||||
private int[] VertexBuffers;
|
private int[] VertexBuffers;
|
||||||
|
|
||||||
|
@ -44,36 +44,29 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public void ClearBuffers(
|
public void ClearBuffers(
|
||||||
GalClearBufferFlags Flags,
|
GalClearBufferFlags Flags,
|
||||||
|
int Attachment,
|
||||||
float Red, float Green, float Blue, float Alpha,
|
float Red, float Green, float Blue, float Alpha,
|
||||||
float Depth,
|
float Depth,
|
||||||
int Stencil)
|
int Stencil)
|
||||||
{
|
{
|
||||||
ClearBufferMask Mask = ClearBufferMask.ColorBufferBit;
|
|
||||||
|
|
||||||
GL.ColorMask(
|
GL.ColorMask(
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorRed),
|
Flags.HasFlag(GalClearBufferFlags.ColorRed),
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorGreen),
|
Flags.HasFlag(GalClearBufferFlags.ColorGreen),
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorBlue),
|
Flags.HasFlag(GalClearBufferFlags.ColorBlue),
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorAlpha));
|
Flags.HasFlag(GalClearBufferFlags.ColorAlpha));
|
||||||
|
|
||||||
|
GL.ClearBuffer(ClearBuffer.Color, Attachment, new float[] { Red, Green, Blue, Alpha });
|
||||||
|
|
||||||
if (Flags.HasFlag(GalClearBufferFlags.Depth))
|
if (Flags.HasFlag(GalClearBufferFlags.Depth))
|
||||||
{
|
{
|
||||||
Mask |= ClearBufferMask.DepthBufferBit;
|
GL.ClearBuffer(ClearBuffer.Depth, 0, ref Depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Flags.HasFlag(GalClearBufferFlags.Stencil))
|
if (Flags.HasFlag(GalClearBufferFlags.Stencil))
|
||||||
{
|
{
|
||||||
Mask |= ClearBufferMask.StencilBufferBit;
|
GL.ClearBuffer(ClearBuffer.Stencil, 0, ref Stencil);
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.ClearColor(Red, Green, Blue, Alpha);
|
|
||||||
|
|
||||||
GL.ClearDepth(Depth);
|
|
||||||
|
|
||||||
GL.ClearStencil(Stencil);
|
|
||||||
|
|
||||||
GL.Clear(Mask);
|
|
||||||
|
|
||||||
GL.ColorMask(true, true, true, true);
|
GL.ColorMask(true, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
Buffer = new OGLConstBuffer();
|
Buffer = new OGLConstBuffer();
|
||||||
|
|
||||||
FrameBuffer = new OGLFrameBuffer();
|
Texture = new OGLTexture();
|
||||||
|
|
||||||
|
FrameBuffer = new OGLFrameBuffer(Texture as OGLTexture);
|
||||||
|
|
||||||
Rasterizer = new OGLRasterizer();
|
Rasterizer = new OGLRasterizer();
|
||||||
|
|
||||||
|
@ -31,8 +33,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
Pipeline = new OGLPipeline(Buffer as OGLConstBuffer, Rasterizer as OGLRasterizer, Shader as OGLShader);
|
Pipeline = new OGLPipeline(Buffer as OGLConstBuffer, Rasterizer as OGLRasterizer, Shader as OGLShader);
|
||||||
|
|
||||||
Texture = new OGLTexture();
|
|
||||||
|
|
||||||
ActionsQueue = new ConcurrentQueue<Action>();
|
ActionsQueue = new ConcurrentQueue<Action>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLShader : IGalShader
|
class OGLShader : IGalShader
|
||||||
{
|
{
|
||||||
|
public const int ReservedCbufCount = 1;
|
||||||
|
|
||||||
|
private const int ExtraDataSize = 4;
|
||||||
|
|
||||||
public OGLShaderProgram Current;
|
public OGLShaderProgram Current;
|
||||||
|
|
||||||
private ConcurrentDictionary<long, OGLShaderStage> Stages;
|
private ConcurrentDictionary<long, OGLShaderStage> Stages;
|
||||||
|
@ -96,16 +100,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return Enumerable.Empty<ShaderDeclInfo>();
|
return Enumerable.Empty<ShaderDeclInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureTextureBinding(string UniformName, int Value)
|
public unsafe void SetExtraData(float FlipX, float FlipY, int Instance)
|
||||||
{
|
|
||||||
BindProgram();
|
|
||||||
|
|
||||||
int Location = GL.GetUniformLocation(CurrentProgramHandle, UniformName);
|
|
||||||
|
|
||||||
GL.Uniform1(Location, Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void SetFlip(float X, float Y)
|
|
||||||
{
|
{
|
||||||
BindProgram();
|
BindProgram();
|
||||||
|
|
||||||
|
@ -113,14 +108,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle);
|
GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle);
|
||||||
|
|
||||||
float* Data = stackalloc float[4];
|
float* Data = stackalloc float[ExtraDataSize];
|
||||||
Data[0] = X;
|
Data[0] = FlipX;
|
||||||
Data[1] = Y;
|
Data[1] = FlipY;
|
||||||
|
Data[2] = BitConverter.Int32BitsToSingle(Instance);
|
||||||
|
|
||||||
//Invalidate buffer
|
//Invalidate buffer
|
||||||
GL.BufferData(BufferTarget.UniformBuffer, 4 * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
|
GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
|
||||||
|
|
||||||
GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, 4 * sizeof(float), (IntPtr)Data);
|
GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, ExtraDataSize * sizeof(float), (IntPtr)Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind(long Key)
|
public void Bind(long Key)
|
||||||
|
@ -188,6 +184,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
CheckProgramLink(Handle);
|
CheckProgramLink(Handle);
|
||||||
|
|
||||||
BindUniformBlocks(Handle);
|
BindUniformBlocks(Handle);
|
||||||
|
BindTextureLocations(Handle);
|
||||||
|
|
||||||
Programs.Add(Current, Handle);
|
Programs.Add(Current, Handle);
|
||||||
}
|
}
|
||||||
|
@ -205,7 +202,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle);
|
GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle);
|
||||||
|
|
||||||
GL.BufferData(BufferTarget.UniformBuffer, 4 * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
|
GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
|
||||||
|
|
||||||
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, ExtraUboHandle);
|
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, ExtraUboHandle);
|
||||||
}
|
}
|
||||||
|
@ -227,8 +224,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.UniformBlockBinding(ProgramHandle, ExtraBlockindex, 0);
|
GL.UniformBlockBinding(ProgramHandle, ExtraBlockindex, 0);
|
||||||
|
|
||||||
//First index is reserved
|
int FreeBinding = ReservedCbufCount;
|
||||||
int FreeBinding = 1;
|
|
||||||
|
|
||||||
void BindUniformBlocksIfNotNull(OGLShaderStage Stage)
|
void BindUniformBlocksIfNotNull(OGLShaderStage Stage)
|
||||||
{
|
{
|
||||||
|
@ -258,6 +254,34 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
BindUniformBlocksIfNotNull(Current.Fragment);
|
BindUniformBlocksIfNotNull(Current.Fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BindTextureLocations(int ProgramHandle)
|
||||||
|
{
|
||||||
|
int Index = 0;
|
||||||
|
|
||||||
|
void BindTexturesIfNotNull(OGLShaderStage Stage)
|
||||||
|
{
|
||||||
|
if (Stage != null)
|
||||||
|
{
|
||||||
|
foreach (ShaderDeclInfo Decl in Stage.TextureUsage)
|
||||||
|
{
|
||||||
|
int Location = GL.GetUniformLocation(ProgramHandle, Decl.Name);
|
||||||
|
|
||||||
|
GL.Uniform1(Location, Index);
|
||||||
|
|
||||||
|
Index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.UseProgram(ProgramHandle);
|
||||||
|
|
||||||
|
BindTexturesIfNotNull(Current.Vertex);
|
||||||
|
BindTexturesIfNotNull(Current.TessControl);
|
||||||
|
BindTexturesIfNotNull(Current.TessEvaluation);
|
||||||
|
BindTexturesIfNotNull(Current.Geometry);
|
||||||
|
BindTexturesIfNotNull(Current.Fragment);
|
||||||
|
}
|
||||||
|
|
||||||
private static void CheckProgramLink(int Handle)
|
private static void CheckProgramLink(int Handle)
|
||||||
{
|
{
|
||||||
int Status = 0;
|
int Status = 0;
|
||||||
|
|
|
@ -4,26 +4,13 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public class OGLTexture : IGalTexture
|
class OGLTexture : IGalTexture
|
||||||
{
|
{
|
||||||
private class TCE
|
private OGLCachedResource<ImageHandler> TextureCache;
|
||||||
{
|
|
||||||
public int Handle;
|
|
||||||
|
|
||||||
public GalTexture Texture;
|
|
||||||
|
|
||||||
public TCE(int Handle, GalTexture Texture)
|
|
||||||
{
|
|
||||||
this.Handle = Handle;
|
|
||||||
this.Texture = Texture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private OGLCachedResource<TCE> TextureCache;
|
|
||||||
|
|
||||||
public OGLTexture()
|
public OGLTexture()
|
||||||
{
|
{
|
||||||
TextureCache = new OGLCachedResource<TCE>(DeleteTexture);
|
TextureCache = new OGLCachedResource<ImageHandler>(DeleteTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LockCache()
|
public void LockCache()
|
||||||
|
@ -36,73 +23,71 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
TextureCache.Unlock();
|
TextureCache.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeleteTexture(TCE CachedTexture)
|
private static void DeleteTexture(ImageHandler CachedImage)
|
||||||
{
|
{
|
||||||
GL.DeleteTexture(CachedTexture.Handle);
|
GL.DeleteTexture(CachedImage.Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create(long Key, byte[] Data, GalTexture Texture)
|
public void Create(long Key, byte[] Data, GalImage Image)
|
||||||
{
|
{
|
||||||
int Handle = GL.GenTexture();
|
int Handle = GL.GenTexture();
|
||||||
|
|
||||||
TextureCache.AddOrUpdate(Key, new TCE(Handle, Texture), (uint)Data.Length);
|
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
|
||||||
const int Level = 0; //TODO: Support mipmap textures.
|
const int Level = 0; //TODO: Support mipmap textures.
|
||||||
const int Border = 0;
|
const int Border = 0;
|
||||||
|
|
||||||
if (IsCompressedTextureFormat(Texture.Format))
|
if (IsCompressedTextureFormat(Image.Format))
|
||||||
{
|
{
|
||||||
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedTextureFormat(Texture.Format);
|
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
|
||||||
|
|
||||||
GL.CompressedTexImage2D(
|
GL.CompressedTexImage2D(
|
||||||
TextureTarget.Texture2D,
|
TextureTarget.Texture2D,
|
||||||
Level,
|
Level,
|
||||||
InternalFmt,
|
InternalFmt,
|
||||||
Texture.Width,
|
Image.Width,
|
||||||
Texture.Height,
|
Image.Height,
|
||||||
Border,
|
Border,
|
||||||
Data.Length,
|
Data.Length,
|
||||||
Data);
|
Data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Texture.Format >= GalTextureFormat.Astc2D4x4)
|
if (Image.Format >= GalImageFormat.ASTC_BEGIN && Image.Format <= GalImageFormat.ASTC_END)
|
||||||
{
|
{
|
||||||
int TextureBlockWidth = GetAstcBlockWidth(Texture.Format);
|
int TextureBlockWidth = GetAstcBlockWidth(Image.Format);
|
||||||
int TextureBlockHeight = GetAstcBlockHeight(Texture.Format);
|
int TextureBlockHeight = GetAstcBlockHeight(Image.Format);
|
||||||
|
|
||||||
Data = ASTCDecoder.DecodeToRGBA8888(
|
Data = ASTCDecoder.DecodeToRGBA8888(
|
||||||
Data,
|
Data,
|
||||||
TextureBlockWidth,
|
TextureBlockWidth,
|
||||||
TextureBlockHeight, 1,
|
TextureBlockHeight, 1,
|
||||||
Texture.Width,
|
Image.Width,
|
||||||
Texture.Height, 1);
|
Image.Height, 1);
|
||||||
|
|
||||||
Texture.Format = GalTextureFormat.A8B8G8R8;
|
Image.Format = GalImageFormat.A8B8G8R8_UNORM_PACK32;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
(PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||||
|
|
||||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(Texture.Format);
|
|
||||||
|
|
||||||
GL.TexImage2D(
|
GL.TexImage2D(
|
||||||
TextureTarget.Texture2D,
|
TextureTarget.Texture2D,
|
||||||
Level,
|
Level,
|
||||||
InternalFmt,
|
InternalFormat,
|
||||||
Texture.Width,
|
Image.Width,
|
||||||
Texture.Height,
|
Image.Height,
|
||||||
Border,
|
Border,
|
||||||
Format,
|
Format,
|
||||||
Type,
|
Type,
|
||||||
Data);
|
Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Texture.XSource);
|
int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource);
|
||||||
int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Texture.YSource);
|
int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource);
|
||||||
int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Texture.ZSource);
|
int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource);
|
||||||
int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Texture.WSource);
|
int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource);
|
||||||
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
|
||||||
|
@ -110,76 +95,100 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetAstcBlockWidth(GalTextureFormat Format)
|
public void CreateFb(long Key, long Size, GalImage Image)
|
||||||
|
{
|
||||||
|
if (!TryGetImage(Key, out ImageHandler CachedImage))
|
||||||
|
{
|
||||||
|
CachedImage = new ImageHandler();
|
||||||
|
|
||||||
|
TextureCache.AddOrUpdate(Key, CachedImage, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
CachedImage.EnsureSetup(Image);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetImage(long Key, out ImageHandler CachedImage)
|
||||||
|
{
|
||||||
|
if (TextureCache.TryGetValue(Key, out CachedImage))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CachedImage = null;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetAstcBlockWidth(GalImageFormat Format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (Format)
|
||||||
{
|
{
|
||||||
case GalTextureFormat.Astc2D4x4: return 4;
|
case GalImageFormat.ASTC_4x4_UNORM_BLOCK: return 4;
|
||||||
case GalTextureFormat.Astc2D5x5: return 5;
|
case GalImageFormat.ASTC_5x5_UNORM_BLOCK: return 5;
|
||||||
case GalTextureFormat.Astc2D6x6: return 6;
|
case GalImageFormat.ASTC_6x6_UNORM_BLOCK: return 6;
|
||||||
case GalTextureFormat.Astc2D8x8: return 8;
|
case GalImageFormat.ASTC_8x8_UNORM_BLOCK: return 8;
|
||||||
case GalTextureFormat.Astc2D10x10: return 10;
|
case GalImageFormat.ASTC_10x10_UNORM_BLOCK: return 10;
|
||||||
case GalTextureFormat.Astc2D12x12: return 12;
|
case GalImageFormat.ASTC_12x12_UNORM_BLOCK: return 12;
|
||||||
case GalTextureFormat.Astc2D5x4: return 5;
|
case GalImageFormat.ASTC_5x4_UNORM_BLOCK: return 5;
|
||||||
case GalTextureFormat.Astc2D6x5: return 6;
|
case GalImageFormat.ASTC_6x5_UNORM_BLOCK: return 6;
|
||||||
case GalTextureFormat.Astc2D8x6: return 8;
|
case GalImageFormat.ASTC_8x6_UNORM_BLOCK: return 8;
|
||||||
case GalTextureFormat.Astc2D10x8: return 10;
|
case GalImageFormat.ASTC_10x8_UNORM_BLOCK: return 10;
|
||||||
case GalTextureFormat.Astc2D12x10: return 12;
|
case GalImageFormat.ASTC_12x10_UNORM_BLOCK: return 12;
|
||||||
case GalTextureFormat.Astc2D8x5: return 8;
|
case GalImageFormat.ASTC_8x5_UNORM_BLOCK: return 8;
|
||||||
case GalTextureFormat.Astc2D10x5: return 10;
|
case GalImageFormat.ASTC_10x5_UNORM_BLOCK: return 10;
|
||||||
case GalTextureFormat.Astc2D10x6: return 10;
|
case GalImageFormat.ASTC_10x6_UNORM_BLOCK: return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Format));
|
throw new ArgumentException(nameof(Format));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetAstcBlockHeight(GalTextureFormat Format)
|
private static int GetAstcBlockHeight(GalImageFormat Format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (Format)
|
||||||
{
|
{
|
||||||
case GalTextureFormat.Astc2D4x4: return 4;
|
case GalImageFormat.ASTC_4x4_UNORM_BLOCK: return 4;
|
||||||
case GalTextureFormat.Astc2D5x5: return 5;
|
case GalImageFormat.ASTC_5x5_UNORM_BLOCK: return 5;
|
||||||
case GalTextureFormat.Astc2D6x6: return 6;
|
case GalImageFormat.ASTC_6x6_UNORM_BLOCK: return 6;
|
||||||
case GalTextureFormat.Astc2D8x8: return 8;
|
case GalImageFormat.ASTC_8x8_UNORM_BLOCK: return 8;
|
||||||
case GalTextureFormat.Astc2D10x10: return 10;
|
case GalImageFormat.ASTC_10x10_UNORM_BLOCK: return 10;
|
||||||
case GalTextureFormat.Astc2D12x12: return 12;
|
case GalImageFormat.ASTC_12x12_UNORM_BLOCK: return 12;
|
||||||
case GalTextureFormat.Astc2D5x4: return 4;
|
case GalImageFormat.ASTC_5x4_UNORM_BLOCK: return 4;
|
||||||
case GalTextureFormat.Astc2D6x5: return 5;
|
case GalImageFormat.ASTC_6x5_UNORM_BLOCK: return 5;
|
||||||
case GalTextureFormat.Astc2D8x6: return 6;
|
case GalImageFormat.ASTC_8x6_UNORM_BLOCK: return 6;
|
||||||
case GalTextureFormat.Astc2D10x8: return 8;
|
case GalImageFormat.ASTC_10x8_UNORM_BLOCK: return 8;
|
||||||
case GalTextureFormat.Astc2D12x10: return 10;
|
case GalImageFormat.ASTC_12x10_UNORM_BLOCK: return 10;
|
||||||
case GalTextureFormat.Astc2D8x5: return 5;
|
case GalImageFormat.ASTC_8x5_UNORM_BLOCK: return 5;
|
||||||
case GalTextureFormat.Astc2D10x5: return 5;
|
case GalImageFormat.ASTC_10x5_UNORM_BLOCK: return 5;
|
||||||
case GalTextureFormat.Astc2D10x6: return 6;
|
case GalImageFormat.ASTC_10x6_UNORM_BLOCK: return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Format));
|
throw new ArgumentException(nameof(Format));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetCachedTexture(long Key, long DataSize, out GalTexture Texture)
|
public bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image)
|
||||||
{
|
{
|
||||||
if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize)
|
if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize)
|
||||||
{
|
{
|
||||||
if (TextureCache.TryGetValue(Key, out TCE CachedTexture))
|
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||||
{
|
{
|
||||||
Texture = CachedTexture.Texture;
|
Image = CachedImage.Image;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture = default(GalTexture);
|
Image = default(GalImage);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind(long Key, int Index)
|
public void Bind(long Key, int Index)
|
||||||
{
|
{
|
||||||
if (TextureCache.TryGetValue(Key, out TCE CachedTexture))
|
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||||
{
|
{
|
||||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, CachedTexture.Handle);
|
GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,18 +217,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color);
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsCompressedTextureFormat(GalTextureFormat Format)
|
private static bool IsCompressedTextureFormat(GalImageFormat Format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (Format)
|
||||||
{
|
{
|
||||||
case GalTextureFormat.BC6H_UF16:
|
case GalImageFormat.BC6H_UFLOAT_BLOCK:
|
||||||
case GalTextureFormat.BC6H_SF16:
|
case GalImageFormat.BC6H_SFLOAT_BLOCK:
|
||||||
case GalTextureFormat.BC7U:
|
case GalImageFormat.BC7_UNORM_BLOCK:
|
||||||
case GalTextureFormat.BC1:
|
case GalImageFormat.BC1_RGBA_UNORM_BLOCK:
|
||||||
case GalTextureFormat.BC2:
|
case GalImageFormat.BC2_UNORM_BLOCK:
|
||||||
case GalTextureFormat.BC3:
|
case GalImageFormat.BC3_UNORM_BLOCK:
|
||||||
case GalTextureFormat.BC4:
|
case GalImageFormat.BC4_SNORM_BLOCK:
|
||||||
case GalTextureFormat.BC5:
|
case GalImageFormat.BC4_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.BC5_SNORM_BLOCK:
|
||||||
|
case GalImageFormat.BC5_UNORM_BLOCK:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public const string ExtraUniformBlockName = "Extra";
|
public const string ExtraUniformBlockName = "Extra";
|
||||||
public const string FlipUniformName = "flip";
|
public const string FlipUniformName = "flip";
|
||||||
|
public const string InstanceUniformName = "instance";
|
||||||
|
|
||||||
public const string ProgramName = "program";
|
public const string BasicBlockName = "bb";
|
||||||
public const string ProgramAName = ProgramName + "_a";
|
public const string BasicBlockAName = BasicBlockName + "_a";
|
||||||
public const string ProgramBName = ProgramName + "_b";
|
public const string BasicBlockBName = BasicBlockName + "_b";
|
||||||
|
|
||||||
|
public const int SsyStackSize = 16;
|
||||||
|
public const string SsyStackName = "ssy_stack";
|
||||||
|
public const string SsyCursorName = "ssy_cursor";
|
||||||
|
|
||||||
private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
|
private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
|
||||||
|
|
||||||
|
@ -93,13 +98,34 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
m_Preds = new Dictionary<int, ShaderDeclInfo>();
|
m_Preds = new Dictionary<int, ShaderDeclInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType) : this(ShaderType)
|
public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType, ShaderHeader Header)
|
||||||
|
: this(ShaderType)
|
||||||
{
|
{
|
||||||
StagePrefix = StagePrefixes[(int)ShaderType] + "_";
|
StagePrefix = StagePrefixes[(int)ShaderType] + "_";
|
||||||
|
|
||||||
if (ShaderType == GalShaderType.Fragment)
|
if (ShaderType == GalShaderType.Fragment)
|
||||||
{
|
{
|
||||||
m_Gprs.Add(0, new ShaderDeclInfo(FragmentOutputName, 0, false, 0, 4));
|
int Index = 0;
|
||||||
|
|
||||||
|
for (int Attachment = 0; Attachment < 8; Attachment++)
|
||||||
|
{
|
||||||
|
for (int Component = 0; Component < 4; Component++)
|
||||||
|
{
|
||||||
|
if (Header.OmapTargets[Attachment].ComponentEnabled(Component))
|
||||||
|
{
|
||||||
|
m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index));
|
||||||
|
|
||||||
|
Index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Header.OmapDepth)
|
||||||
|
{
|
||||||
|
Index = Header.DepthRegister;
|
||||||
|
|
||||||
|
m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ShaderIrBlock Block in Blocks)
|
foreach (ShaderIrBlock Block in Blocks)
|
||||||
|
@ -148,6 +174,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return Combined;
|
return Combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetGprName(int Index)
|
||||||
|
{
|
||||||
|
return GprName + Index;
|
||||||
|
}
|
||||||
|
|
||||||
private static void Merge(
|
private static void Merge(
|
||||||
Dictionary<int, ShaderDeclInfo> C,
|
Dictionary<int, ShaderDeclInfo> C,
|
||||||
Dictionary<int, ShaderDeclInfo> A,
|
Dictionary<int, ShaderDeclInfo> A,
|
||||||
|
@ -311,9 +342,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
case ShaderIrOperGpr Gpr:
|
case ShaderIrOperGpr Gpr:
|
||||||
{
|
{
|
||||||
if (!Gpr.IsConst && !HasName(m_Gprs, Gpr.Index))
|
if (!Gpr.IsConst)
|
||||||
{
|
{
|
||||||
string Name = GprName + Gpr.Index;
|
string Name = GetGprName(Gpr.Index);
|
||||||
|
|
||||||
m_Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index));
|
m_Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index));
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,8 +120,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Blocks = ShaderDecoder.Decode(Memory, VpAPosition);
|
Blocks = ShaderDecoder.Decode(Memory, VpAPosition);
|
||||||
BlocksB = ShaderDecoder.Decode(Memory, VpBPosition);
|
BlocksB = ShaderDecoder.Decode(Memory, VpBPosition);
|
||||||
|
|
||||||
GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType);
|
GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType, Header);
|
||||||
GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType);
|
GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType, HeaderB);
|
||||||
|
|
||||||
Decl = GlslDecl.Merge(DeclVpA, DeclVpB);
|
Decl = GlslDecl.Merge(DeclVpA, DeclVpB);
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Blocks = ShaderDecoder.Decode(Memory, Position);
|
Blocks = ShaderDecoder.Decode(Memory, Position);
|
||||||
BlocksB = null;
|
BlocksB = null;
|
||||||
|
|
||||||
Decl = new GlslDecl(Blocks, ShaderType);
|
Decl = new GlslDecl(Blocks, ShaderType, Header);
|
||||||
|
|
||||||
return Decompile();
|
return Decompile();
|
||||||
}
|
}
|
||||||
|
@ -155,18 +155,19 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
PrintDeclOutAttributes();
|
PrintDeclOutAttributes();
|
||||||
PrintDeclGprs();
|
PrintDeclGprs();
|
||||||
PrintDeclPreds();
|
PrintDeclPreds();
|
||||||
|
PrintDeclSsy();
|
||||||
|
|
||||||
if (BlocksB != null)
|
if (BlocksB != null)
|
||||||
{
|
{
|
||||||
PrintBlockScope(Blocks[0], null, null, "void " + GlslDecl.ProgramAName + "()", IdentationStr);
|
PrintBlockScope(Blocks, GlslDecl.BasicBlockAName);
|
||||||
|
|
||||||
SB.AppendLine();
|
SB.AppendLine();
|
||||||
|
|
||||||
PrintBlockScope(BlocksB[0], null, null, "void " + GlslDecl.ProgramBName + "()", IdentationStr);
|
PrintBlockScope(BlocksB, GlslDecl.BasicBlockBName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PrintBlockScope(Blocks[0], null, null, "void " + GlslDecl.ProgramName + "()", IdentationStr);
|
PrintBlockScope(Blocks, GlslDecl.BasicBlockName);
|
||||||
}
|
}
|
||||||
|
|
||||||
SB.AppendLine();
|
SB.AppendLine();
|
||||||
|
@ -241,10 +242,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
if (Decl.ShaderType == GalShaderType.Vertex)
|
if (Decl.ShaderType == GalShaderType.Vertex)
|
||||||
{
|
{
|
||||||
SB.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + "{");
|
//Memory layout here is [flip_x, flip_y, instance, unused]
|
||||||
|
//It's using 4 bytes, not 8
|
||||||
|
|
||||||
|
SB.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + " {");
|
||||||
|
|
||||||
SB.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";");
|
SB.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";");
|
||||||
|
|
||||||
|
SB.AppendLine(IdentationStr + "int " + GlslDecl.InstanceUniformName + ";");
|
||||||
|
|
||||||
SB.AppendLine("};");
|
SB.AppendLine("};");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +310,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private void PrintDeclOutAttributes()
|
private void PrintDeclOutAttributes()
|
||||||
{
|
{
|
||||||
if (Decl.ShaderType != GalShaderType.Fragment)
|
if (Decl.ShaderType == GalShaderType.Fragment)
|
||||||
|
{
|
||||||
|
for (int Attachment = 0; Attachment < 8; Attachment++)
|
||||||
|
{
|
||||||
|
if (Header.OmapTargets[Attachment].Enabled)
|
||||||
|
{
|
||||||
|
SB.AppendLine("layout (location = " + Attachment + ") out vec4 " + GlslDecl.FragmentOutputName + Attachment + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
SB.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";");
|
SB.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||||
}
|
}
|
||||||
|
@ -342,6 +358,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
PrintDecls(Decl.Preds, "bool");
|
PrintDecls(Decl.Preds, "bool");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PrintDeclSsy()
|
||||||
|
{
|
||||||
|
SB.AppendLine("uint " + GlslDecl.SsyCursorName + ";");
|
||||||
|
|
||||||
|
SB.AppendLine("uint " + GlslDecl.SsyStackName + "[" + GlslDecl.SsyStackSize + "];" + Environment.NewLine);
|
||||||
|
}
|
||||||
|
|
||||||
private void PrintDecls(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, string CustomType = null, string Suffix = "")
|
private void PrintDecls(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, string CustomType = null, string Suffix = "")
|
||||||
{
|
{
|
||||||
foreach (ShaderDeclInfo DeclInfo in Dict.Values.OrderBy(DeclKeySelector))
|
foreach (ShaderDeclInfo DeclInfo in Dict.Values.OrderBy(DeclKeySelector))
|
||||||
|
@ -352,9 +375,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
Name = CustomType + " " + DeclInfo.Name + Suffix + ";";
|
Name = CustomType + " " + DeclInfo.Name + Suffix + ";";
|
||||||
}
|
}
|
||||||
else if (DeclInfo.Name == GlslDecl.FragmentOutputName)
|
else if (DeclInfo.Name.Contains(GlslDecl.FragmentOutputName))
|
||||||
{
|
{
|
||||||
Name = "layout (location = 0) out vec4 " + DeclInfo.Name + Suffix + ";" + Environment.NewLine;
|
Name = "layout (location = " + DeclInfo.Index / 4 + ") out vec4 " + DeclInfo.Name + Suffix + ";";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -417,14 +440,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SB.AppendLine(IdentationStr + "uint pc;");
|
||||||
|
|
||||||
if (BlocksB != null)
|
if (BlocksB != null)
|
||||||
{
|
{
|
||||||
SB.AppendLine(IdentationStr + GlslDecl.ProgramAName + "();");
|
PrintProgram(Blocks, GlslDecl.BasicBlockAName);
|
||||||
SB.AppendLine(IdentationStr + GlslDecl.ProgramBName + "();");
|
PrintProgram(BlocksB, GlslDecl.BasicBlockBName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SB.AppendLine(IdentationStr + GlslDecl.ProgramName + "();");
|
PrintProgram(Blocks, GlslDecl.BasicBlockName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Decl.ShaderType != GalShaderType.Geometry)
|
if (Decl.ShaderType != GalShaderType.Geometry)
|
||||||
|
@ -432,9 +457,62 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
PrintAttrToOutput();
|
PrintAttrToOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Decl.ShaderType == GalShaderType.Fragment)
|
||||||
|
{
|
||||||
|
if (Header.OmapDepth)
|
||||||
|
{
|
||||||
|
SB.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(Header.DepthRegister) + ";");
|
||||||
|
}
|
||||||
|
|
||||||
|
int GprIndex = 0;
|
||||||
|
|
||||||
|
for (int Attachment = 0; Attachment < 8; Attachment++)
|
||||||
|
{
|
||||||
|
string Output = GlslDecl.FragmentOutputName + Attachment;
|
||||||
|
|
||||||
|
OmapTarget Target = Header.OmapTargets[Attachment];
|
||||||
|
|
||||||
|
for (int Component = 0; Component < 4; Component++)
|
||||||
|
{
|
||||||
|
if (Target.ComponentEnabled(Component))
|
||||||
|
{
|
||||||
|
SB.AppendLine(IdentationStr + Output + "[" + Component + "] = " + GlslDecl.GetGprName(GprIndex) + ";");
|
||||||
|
|
||||||
|
GprIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SB.AppendLine("}");
|
SB.AppendLine("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PrintProgram(ShaderIrBlock[] Blocks, string Name)
|
||||||
|
{
|
||||||
|
const string Ident1 = IdentationStr;
|
||||||
|
const string Ident2 = Ident1 + IdentationStr;
|
||||||
|
const string Ident3 = Ident2 + IdentationStr;
|
||||||
|
const string Ident4 = Ident3 + IdentationStr;
|
||||||
|
|
||||||
|
SB.AppendLine(Ident1 + "pc = " + GetBlockPosition(Blocks[0]) + ";");
|
||||||
|
SB.AppendLine(Ident1 + "do {");
|
||||||
|
SB.AppendLine(Ident2 + "switch (pc) {");
|
||||||
|
|
||||||
|
foreach (ShaderIrBlock Block in Blocks)
|
||||||
|
{
|
||||||
|
string FunctionName = Block.Position.ToString("x8");
|
||||||
|
|
||||||
|
SB.AppendLine(Ident3 + "case 0x" + FunctionName + ": pc = " + Name + "_" + FunctionName + "(); break;");
|
||||||
|
}
|
||||||
|
|
||||||
|
SB.AppendLine(Ident3 + "default:");
|
||||||
|
SB.AppendLine(Ident4 + "pc = 0;");
|
||||||
|
SB.AppendLine(Ident4 + "break;");
|
||||||
|
|
||||||
|
SB.AppendLine(Ident2 + "}");
|
||||||
|
SB.AppendLine(Ident1 + "} while (pc != 0);");
|
||||||
|
}
|
||||||
|
|
||||||
private void PrintAttrToOutput(string Identation = IdentationStr)
|
private void PrintAttrToOutput(string Identation = IdentationStr)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<int, ShaderDeclInfo> KV in Decl.OutAttributes)
|
foreach (KeyValuePair<int, ShaderDeclInfo> KV in Decl.OutAttributes)
|
||||||
|
@ -468,75 +546,19 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintBlockScope(
|
private void PrintBlockScope(ShaderIrBlock[] Blocks, string Name)
|
||||||
ShaderIrBlock Block,
|
|
||||||
ShaderIrBlock EndBlock,
|
|
||||||
ShaderIrBlock LoopBlock,
|
|
||||||
string ScopeName,
|
|
||||||
string Identation,
|
|
||||||
bool IsDoWhile = false)
|
|
||||||
{
|
{
|
||||||
string UpIdent = Identation.Substring(0, Identation.Length - IdentationStr.Length);
|
foreach (ShaderIrBlock Block in Blocks)
|
||||||
|
{
|
||||||
|
SB.AppendLine("uint " + Name + "_" + Block.Position.ToString("x8") + "() {");
|
||||||
|
|
||||||
if (IsDoWhile)
|
PrintNodes(Block, Block.GetNodes());
|
||||||
{
|
|
||||||
SB.AppendLine(UpIdent + "do {");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SB.AppendLine(UpIdent + ScopeName + " {");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (Block != null && Block != EndBlock)
|
SB.AppendLine("}" + Environment.NewLine);
|
||||||
{
|
|
||||||
ShaderIrNode[] Nodes = Block.GetNodes();
|
|
||||||
|
|
||||||
Block = PrintNodes(Block, EndBlock, LoopBlock, Identation, Nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsDoWhile)
|
|
||||||
{
|
|
||||||
SB.AppendLine(UpIdent + "} " + ScopeName + ";");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SB.AppendLine(UpIdent + "}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ShaderIrBlock PrintNodes(
|
private void PrintNode(ShaderIrBlock Block, ShaderIrNode Node, string Identation)
|
||||||
ShaderIrBlock Block,
|
|
||||||
ShaderIrBlock EndBlock,
|
|
||||||
ShaderIrBlock LoopBlock,
|
|
||||||
string Identation,
|
|
||||||
params ShaderIrNode[] Nodes)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Notes about control flow and if-else/loop generation:
|
|
||||||
* The code assumes that the program has sane control flow,
|
|
||||||
* that is, there's no jumps to a location after another jump or
|
|
||||||
* jump target (except for the end of an if-else block), and backwards
|
|
||||||
* jumps to a location before the last loop dominator.
|
|
||||||
* Such cases needs to be transformed on a step before the GLSL code
|
|
||||||
* generation to ensure that we have sane graphs to work with.
|
|
||||||
* TODO: Such transformation is not yet implemented.
|
|
||||||
*/
|
|
||||||
string NewIdent = Identation + IdentationStr;
|
|
||||||
|
|
||||||
ShaderIrBlock LoopTail = GetLoopTailBlock(Block);
|
|
||||||
|
|
||||||
if (LoopTail != null && LoopBlock != Block)
|
|
||||||
{
|
|
||||||
//Shoock! kuma shock! We have a loop here!
|
|
||||||
//The entire sequence needs to be inside a do-while block.
|
|
||||||
ShaderIrBlock LoopEnd = GetDownBlock(LoopTail);
|
|
||||||
|
|
||||||
PrintBlockScope(Block, LoopEnd, Block, "while (false)", NewIdent, IsDoWhile: true);
|
|
||||||
|
|
||||||
return LoopEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (ShaderIrNode Node in Nodes)
|
|
||||||
{
|
{
|
||||||
if (Node is ShaderIrCond Cond)
|
if (Node is ShaderIrCond Cond)
|
||||||
{
|
{
|
||||||
|
@ -547,44 +569,19 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
IfExpr = "!(" + IfExpr + ")";
|
IfExpr = "!(" + IfExpr + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Cond.Child is ShaderIrOp Op && Op.Inst == ShaderIrInst.Bra)
|
|
||||||
{
|
|
||||||
//Branch is a loop branch and would result in infinite recursion.
|
|
||||||
if (Block.Branch.Position <= Block.Position)
|
|
||||||
{
|
|
||||||
SB.AppendLine(Identation + "if (" + IfExpr + ") {");
|
SB.AppendLine(Identation + "if (" + IfExpr + ") {");
|
||||||
|
|
||||||
SB.AppendLine(Identation + IdentationStr + "continue;");
|
if (Cond.Child is ShaderIrOp Op && Op.Inst == ShaderIrInst.Bra)
|
||||||
|
|
||||||
SB.AppendLine(Identation + "}");
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string SubScopeName = "if (!" + IfExpr + ")";
|
|
||||||
|
|
||||||
PrintBlockScope(Block.Next, Block.Branch, LoopBlock, SubScopeName, NewIdent);
|
|
||||||
|
|
||||||
ShaderIrBlock IfElseEnd = GetUpBlock(Block.Branch).Branch;
|
|
||||||
|
|
||||||
if (IfElseEnd?.Position > Block.Branch.Position)
|
|
||||||
{
|
{
|
||||||
PrintBlockScope(Block.Branch, IfElseEnd, LoopBlock, "else", NewIdent);
|
SB.AppendLine(Identation + IdentationStr + "return " + GetBlockPosition(Block.Branch) + ";");
|
||||||
|
|
||||||
return IfElseEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Block.Branch;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SB.AppendLine(Identation + "if (" + IfExpr + ") {");
|
PrintNode(Block, Cond.Child, Identation + IdentationStr);
|
||||||
|
}
|
||||||
PrintNodes(Block, EndBlock, LoopBlock, NewIdent, Cond.Child);
|
|
||||||
|
|
||||||
SB.AppendLine(Identation + "}");
|
SB.AppendLine(Identation + "}");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (Node is ShaderIrAsg Asg)
|
else if (Node is ShaderIrAsg Asg)
|
||||||
{
|
{
|
||||||
if (IsValidOutOper(Asg.Dst))
|
if (IsValidOutOper(Asg.Dst))
|
||||||
|
@ -598,22 +595,53 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
else if (Node is ShaderIrOp Op)
|
else if (Node is ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
if (Op.Inst == ShaderIrInst.Bra)
|
switch (Op.Inst)
|
||||||
{
|
{
|
||||||
if (Block.Branch.Position <= Block.Position)
|
case ShaderIrInst.Bra:
|
||||||
{
|
{
|
||||||
SB.AppendLine(Identation + "continue;");
|
SB.AppendLine(Identation + "return " + GetBlockPosition(Block.Branch) + ";");
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (Op.Inst == ShaderIrInst.Emit)
|
case ShaderIrInst.Emit:
|
||||||
{
|
{
|
||||||
PrintAttrToOutput(Identation);
|
PrintAttrToOutput(Identation);
|
||||||
|
|
||||||
SB.AppendLine(Identation + "EmitVertex();");
|
SB.AppendLine(Identation + "EmitVertex();");
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
case ShaderIrInst.Ssy:
|
||||||
{
|
{
|
||||||
|
string StackIndex = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]";
|
||||||
|
|
||||||
|
int TargetPosition = (Op.OperandA as ShaderIrOperImm).Value;
|
||||||
|
|
||||||
|
string Target = "0x" + TargetPosition.ToString("x8") + "u";
|
||||||
|
|
||||||
|
SB.AppendLine(Identation + StackIndex + " = " + Target + ";");
|
||||||
|
|
||||||
|
SB.AppendLine(Identation + GlslDecl.SsyCursorName + "++;");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrInst.Sync:
|
||||||
|
{
|
||||||
|
SB.AppendLine(Identation + GlslDecl.SsyCursorName + "--;");
|
||||||
|
|
||||||
|
string Target = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]";
|
||||||
|
|
||||||
|
SB.AppendLine(Identation + "return " + Target + ";");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Node is ShaderIrCmnt Cmnt)
|
else if (Node is ShaderIrCmnt Cmnt)
|
||||||
|
@ -626,35 +654,37 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Block.Next;
|
private void PrintNodes(ShaderIrBlock Block, ShaderIrNode[] Nodes)
|
||||||
|
{
|
||||||
|
foreach (ShaderIrNode Node in Nodes)
|
||||||
|
{
|
||||||
|
PrintNode(Block, Node, IdentationStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ShaderIrBlock GetUpBlock(ShaderIrBlock Block)
|
if (Nodes.Length > 0)
|
||||||
{
|
{
|
||||||
return Blocks.FirstOrDefault(x => x.EndPosition == Block.Position);
|
ShaderIrNode Last = Nodes[Nodes.Length - 1];
|
||||||
}
|
|
||||||
|
|
||||||
private ShaderIrBlock GetDownBlock(ShaderIrBlock Block)
|
bool UnconditionalFlowChange = false;
|
||||||
{
|
|
||||||
return Blocks.FirstOrDefault(x => x.Position == Block.EndPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShaderIrBlock GetLoopTailBlock(ShaderIrBlock LoopHead)
|
if (Last is ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
ShaderIrBlock Tail = null;
|
switch (Op.Inst)
|
||||||
|
|
||||||
foreach (ShaderIrBlock Block in LoopHead.Sources)
|
|
||||||
{
|
{
|
||||||
if (Block.Position >= LoopHead.Position)
|
case ShaderIrInst.Bra:
|
||||||
{
|
case ShaderIrInst.Exit:
|
||||||
if (Tail == null || Tail.Position < Block.Position)
|
case ShaderIrInst.Kil:
|
||||||
{
|
case ShaderIrInst.Sync:
|
||||||
Tail = Block;
|
UnconditionalFlowChange = true;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Tail;
|
if (!UnconditionalFlowChange)
|
||||||
|
{
|
||||||
|
SB.AppendLine(IdentationStr + "return " + GetBlockPosition(Block.Next) + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsValidOutOper(ShaderIrNode Node)
|
private bool IsValidOutOper(ShaderIrNode Node)
|
||||||
|
@ -779,7 +809,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
switch (Abuf.Offs)
|
switch (Abuf.Offs)
|
||||||
{
|
{
|
||||||
case GlslDecl.VertexIdAttr: return "gl_VertexID";
|
case GlslDecl.VertexIdAttr: return "gl_VertexID";
|
||||||
case GlslDecl.InstanceIdAttr: return "gl_InstanceID";
|
case GlslDecl.InstanceIdAttr: return GlslDecl.InstanceUniformName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Decl.ShaderType == GalShaderType.TessEvaluation)
|
else if (Decl.ShaderType == GalShaderType.TessEvaluation)
|
||||||
|
@ -829,8 +859,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
return "gl_PointSize";
|
return "gl_PointSize";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw new InvalidOperationException();
|
if (DeclInfo.Index >= 16)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Shader attribute offset {Abuf.Offs} is invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Decl.ShaderType == GalShaderType.Geometry)
|
if (Decl.ShaderType == GalShaderType.Geometry)
|
||||||
|
@ -876,7 +909,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetNameWithSwizzle(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, int Index)
|
private string GetNameWithSwizzle(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, int Index)
|
||||||
{
|
{
|
||||||
int VecIndex = Index >> 2;
|
int VecIndex = Index & ~3;
|
||||||
|
|
||||||
if (Dict.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo))
|
if (Dict.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo))
|
||||||
{
|
{
|
||||||
|
@ -961,7 +994,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetCnumExpr(ShaderIrOp Op) => GetUnaryCall(Op, "!isnan");
|
private string GetCnumExpr(ShaderIrOp Op) => GetUnaryCall(Op, "!isnan");
|
||||||
|
|
||||||
private string GetExitExpr(ShaderIrOp Op) => "return";
|
private string GetExitExpr(ShaderIrOp Op) => "return 0u";
|
||||||
|
|
||||||
private string GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos");
|
private string GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos");
|
||||||
|
|
||||||
|
@ -993,7 +1026,31 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return "int(uint(" + GetOperExpr(Op, Op.OperandA) + "))";
|
return "int(uint(" + GetOperExpr(Op, Op.OperandA) + "))";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetIpaExpr(ShaderIrOp Op) => GetSrcExpr(Op.OperandA);
|
private string GetIpaExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
ShaderIrMetaIpa Meta = (ShaderIrMetaIpa)Op.MetaData;
|
||||||
|
|
||||||
|
ShaderIrOperAbuf Abuf = (ShaderIrOperAbuf)Op.OperandA;
|
||||||
|
|
||||||
|
if (Meta.Mode == ShaderIpaMode.Pass)
|
||||||
|
{
|
||||||
|
int Index = Abuf.Offs >> 4;
|
||||||
|
int Elem = (Abuf.Offs >> 2) & 3;
|
||||||
|
|
||||||
|
if (Decl.ShaderType == GalShaderType.Fragment && Index == GlslDecl.GlPositionVec4Index)
|
||||||
|
{
|
||||||
|
switch (Elem)
|
||||||
|
{
|
||||||
|
case 0: return "gl_FragCoord.x";
|
||||||
|
case 1: return "gl_FragCoord.y";
|
||||||
|
case 2: return "gl_FragCoord.z";
|
||||||
|
case 3: return "1";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetSrcExpr(Op.OperandA);
|
||||||
|
}
|
||||||
|
|
||||||
private string GetKilExpr(ShaderIrOp Op) => "discard";
|
private string GetKilExpr(ShaderIrOp Op) => "discard";
|
||||||
|
|
||||||
|
@ -1306,5 +1363,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
throw new ArgumentException(nameof(Node));
|
throw new ArgumentException(nameof(Node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetBlockPosition(ShaderIrBlock Block)
|
||||||
|
{
|
||||||
|
if (Block != null)
|
||||||
|
{
|
||||||
|
return "0x" + Block.Position.ToString("x8") + "u";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "0u";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode);
|
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, long Position);
|
||||||
}
|
}
|
|
@ -6,32 +6,32 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
public static void Bfe_C(ShaderIrBlock Block, long OpCode)
|
public static void Bfe_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitBfe(Block, OpCode, ShaderOper.CR);
|
EmitBfe(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Bfe_I(ShaderIrBlock Block, long OpCode)
|
public static void Bfe_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitBfe(Block, OpCode, ShaderOper.Imm);
|
EmitBfe(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Bfe_R(ShaderIrBlock Block, long OpCode)
|
public static void Bfe_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitBfe(Block, OpCode, ShaderOper.RR);
|
EmitBfe(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fadd_C(ShaderIrBlock Block, long OpCode)
|
public static void Fadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFadd(Block, OpCode, ShaderOper.CR);
|
EmitFadd(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fadd_I(ShaderIrBlock Block, long OpCode)
|
public static void Fadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFadd(Block, OpCode, ShaderOper.Immf);
|
EmitFadd(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fadd_I32(ShaderIrBlock Block, long OpCode)
|
public static void Fadd_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
||||||
ShaderIrNode OperB = GetOperImmf32_20(OpCode);
|
ShaderIrNode OperB = GetOperImmf32_20(OpCode);
|
||||||
|
@ -49,47 +49,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fadd_R(ShaderIrBlock Block, long OpCode)
|
public static void Fadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFadd(Block, OpCode, ShaderOper.RR);
|
EmitFadd(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ffma_CR(ShaderIrBlock Block, long OpCode)
|
public static void Ffma_CR(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFfma(Block, OpCode, ShaderOper.CR);
|
EmitFfma(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ffma_I(ShaderIrBlock Block, long OpCode)
|
public static void Ffma_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFfma(Block, OpCode, ShaderOper.Immf);
|
EmitFfma(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ffma_RC(ShaderIrBlock Block, long OpCode)
|
public static void Ffma_RC(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFfma(Block, OpCode, ShaderOper.RC);
|
EmitFfma(Block, OpCode, ShaderOper.RC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ffma_RR(ShaderIrBlock Block, long OpCode)
|
public static void Ffma_RR(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFfma(Block, OpCode, ShaderOper.RR);
|
EmitFfma(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmnmx_C(ShaderIrBlock Block, long OpCode)
|
public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFmnmx(Block, OpCode, ShaderOper.CR);
|
EmitFmnmx(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmnmx_I(ShaderIrBlock Block, long OpCode)
|
public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFmnmx(Block, OpCode, ShaderOper.Immf);
|
EmitFmnmx(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmnmx_R(ShaderIrBlock Block, long OpCode)
|
public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFmnmx(Block, OpCode, ShaderOper.RR);
|
EmitFmnmx(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmul_I32(ShaderIrBlock Block, long OpCode)
|
public static void Fmul_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
||||||
ShaderIrNode OperB = GetOperImmf32_20(OpCode);
|
ShaderIrNode OperB = GetOperImmf32_20(OpCode);
|
||||||
|
@ -99,62 +99,62 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmul_C(ShaderIrBlock Block, long OpCode)
|
public static void Fmul_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFmul(Block, OpCode, ShaderOper.CR);
|
EmitFmul(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmul_I(ShaderIrBlock Block, long OpCode)
|
public static void Fmul_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFmul(Block, OpCode, ShaderOper.Immf);
|
EmitFmul(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmul_R(ShaderIrBlock Block, long OpCode)
|
public static void Fmul_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFmul(Block, OpCode, ShaderOper.RR);
|
EmitFmul(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fset_C(ShaderIrBlock Block, long OpCode)
|
public static void Fset_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFset(Block, OpCode, ShaderOper.CR);
|
EmitFset(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fset_I(ShaderIrBlock Block, long OpCode)
|
public static void Fset_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFset(Block, OpCode, ShaderOper.Immf);
|
EmitFset(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fset_R(ShaderIrBlock Block, long OpCode)
|
public static void Fset_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFset(Block, OpCode, ShaderOper.RR);
|
EmitFset(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fsetp_C(ShaderIrBlock Block, long OpCode)
|
public static void Fsetp_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFsetp(Block, OpCode, ShaderOper.CR);
|
EmitFsetp(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fsetp_I(ShaderIrBlock Block, long OpCode)
|
public static void Fsetp_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFsetp(Block, OpCode, ShaderOper.Immf);
|
EmitFsetp(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fsetp_R(ShaderIrBlock Block, long OpCode)
|
public static void Fsetp_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitFsetp(Block, OpCode, ShaderOper.RR);
|
EmitFsetp(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd_C(ShaderIrBlock Block, long OpCode)
|
public static void Iadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIadd(Block, OpCode, ShaderOper.CR);
|
EmitIadd(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd_I(ShaderIrBlock Block, long OpCode)
|
public static void Iadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIadd(Block, OpCode, ShaderOper.Imm);
|
EmitIadd(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd_I32(ShaderIrBlock Block, long OpCode)
|
public static void Iadd_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
||||||
ShaderIrNode OperB = GetOperImm32_20(OpCode);
|
ShaderIrNode OperB = GetOperImm32_20(OpCode);
|
||||||
|
@ -168,97 +168,101 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd_R(ShaderIrBlock Block, long OpCode)
|
public static void Iadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIadd(Block, OpCode, ShaderOper.RR);
|
EmitIadd(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd3_C(ShaderIrBlock Block, long OpCode)
|
public static void Iadd3_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIadd3(Block, OpCode, ShaderOper.CR);
|
EmitIadd3(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd3_I(ShaderIrBlock Block, long OpCode)
|
public static void Iadd3_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIadd3(Block, OpCode, ShaderOper.Imm);
|
EmitIadd3(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iadd3_R(ShaderIrBlock Block, long OpCode)
|
public static void Iadd3_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIadd3(Block, OpCode, ShaderOper.RR);
|
EmitIadd3(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Imnmx_C(ShaderIrBlock Block, long OpCode)
|
public static void Imnmx_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitImnmx(Block, OpCode, ShaderOper.CR);
|
EmitImnmx(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Imnmx_I(ShaderIrBlock Block, long OpCode)
|
public static void Imnmx_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitImnmx(Block, OpCode, ShaderOper.Imm);
|
EmitImnmx(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Imnmx_R(ShaderIrBlock Block, long OpCode)
|
public static void Imnmx_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitImnmx(Block, OpCode, ShaderOper.RR);
|
EmitImnmx(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ipa(ShaderIrBlock Block, long OpCode)
|
public static void Ipa(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = GetOperAbuf28(OpCode);
|
ShaderIrNode OperA = GetOperAbuf28(OpCode);
|
||||||
ShaderIrNode OperB = GetOperGpr20 (OpCode);
|
ShaderIrNode OperB = GetOperGpr20 (OpCode);
|
||||||
|
|
||||||
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ipa, OperA, OperB);
|
ShaderIpaMode Mode = (ShaderIpaMode)((OpCode >> 54) & 3);
|
||||||
|
|
||||||
|
ShaderIrMetaIpa Meta = new ShaderIrMetaIpa(Mode);
|
||||||
|
|
||||||
|
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ipa, OperA, OperB, null, Meta);
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iscadd_C(ShaderIrBlock Block, long OpCode)
|
public static void Iscadd_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIscadd(Block, OpCode, ShaderOper.CR);
|
EmitIscadd(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iscadd_I(ShaderIrBlock Block, long OpCode)
|
public static void Iscadd_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIscadd(Block, OpCode, ShaderOper.Imm);
|
EmitIscadd(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iscadd_R(ShaderIrBlock Block, long OpCode)
|
public static void Iscadd_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIscadd(Block, OpCode, ShaderOper.RR);
|
EmitIscadd(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iset_C(ShaderIrBlock Block, long OpCode)
|
public static void Iset_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIset(Block, OpCode, ShaderOper.CR);
|
EmitIset(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iset_I(ShaderIrBlock Block, long OpCode)
|
public static void Iset_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIset(Block, OpCode, ShaderOper.Imm);
|
EmitIset(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Iset_R(ShaderIrBlock Block, long OpCode)
|
public static void Iset_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIset(Block, OpCode, ShaderOper.RR);
|
EmitIset(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isetp_C(ShaderIrBlock Block, long OpCode)
|
public static void Isetp_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIsetp(Block, OpCode, ShaderOper.CR);
|
EmitIsetp(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isetp_I(ShaderIrBlock Block, long OpCode)
|
public static void Isetp_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIsetp(Block, OpCode, ShaderOper.Imm);
|
EmitIsetp(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isetp_R(ShaderIrBlock Block, long OpCode)
|
public static void Isetp_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitIsetp(Block, OpCode, ShaderOper.RR);
|
EmitIsetp(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Lop_I32(ShaderIrBlock Block, long OpCode)
|
public static void Lop_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
int SubOp = (int)(OpCode >> 53) & 3;
|
int SubOp = (int)(OpCode >> 53) & 3;
|
||||||
|
|
||||||
|
@ -292,22 +296,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Lop_C(ShaderIrBlock Block, long OpCode)
|
public static void Lop_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitLop(Block, OpCode, ShaderOper.CR);
|
EmitLop(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Lop_I(ShaderIrBlock Block, long OpCode)
|
public static void Lop_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitLop(Block, OpCode, ShaderOper.Imm);
|
EmitLop(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Lop_R(ShaderIrBlock Block, long OpCode)
|
public static void Lop_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitLop(Block, OpCode, ShaderOper.RR);
|
EmitLop(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mufu(ShaderIrBlock Block, long OpCode)
|
public static void Mufu(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
int SubOp = (int)(OpCode >> 20) & 0xf;
|
int SubOp = (int)(OpCode >> 20) & 0xf;
|
||||||
|
|
||||||
|
@ -336,7 +340,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Psetp(ShaderIrBlock Block, long OpCode)
|
public static void Psetp(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
bool NegA = ((OpCode >> 15) & 1) != 0;
|
bool NegA = ((OpCode >> 15) & 1) != 0;
|
||||||
bool NegB = ((OpCode >> 32) & 1) != 0;
|
bool NegB = ((OpCode >> 32) & 1) != 0;
|
||||||
|
@ -390,47 +394,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Rro_C(ShaderIrBlock Block, long OpCode)
|
public static void Rro_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitRro(Block, OpCode, ShaderOper.CR);
|
EmitRro(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Rro_I(ShaderIrBlock Block, long OpCode)
|
public static void Rro_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitRro(Block, OpCode, ShaderOper.Immf);
|
EmitRro(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Rro_R(ShaderIrBlock Block, long OpCode)
|
public static void Rro_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitRro(Block, OpCode, ShaderOper.RR);
|
EmitRro(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shl_C(ShaderIrBlock Block, long OpCode)
|
public static void Shl_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
|
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shl_I(ShaderIrBlock Block, long OpCode)
|
public static void Shl_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl);
|
EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shl_R(ShaderIrBlock Block, long OpCode)
|
public static void Shl_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl);
|
EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shr_C(ShaderIrBlock Block, long OpCode)
|
public static void Shr_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
|
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shr_I(ShaderIrBlock Block, long OpCode)
|
public static void Shr_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode));
|
EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shr_R(ShaderIrBlock Block, long OpCode)
|
public static void Shr_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode));
|
EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode));
|
||||||
}
|
}
|
||||||
|
@ -442,7 +446,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Vmad(ShaderIrBlock Block, long OpCode)
|
public static void Vmad(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperA = GetOperGpr8(OpCode);
|
ShaderIrNode OperA = GetOperGpr8(OpCode);
|
||||||
|
|
||||||
|
@ -477,22 +481,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Final), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Final), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Xmad_CR(ShaderIrBlock Block, long OpCode)
|
public static void Xmad_CR(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitXmad(Block, OpCode, ShaderOper.CR);
|
EmitXmad(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Xmad_I(ShaderIrBlock Block, long OpCode)
|
public static void Xmad_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitXmad(Block, OpCode, ShaderOper.Imm);
|
EmitXmad(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Xmad_RC(ShaderIrBlock Block, long OpCode)
|
public static void Xmad_RC(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitXmad(Block, OpCode, ShaderOper.RC);
|
EmitXmad(Block, OpCode, ShaderOper.RC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Xmad_RR(ShaderIrBlock Block, long OpCode)
|
public static void Xmad_RR(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitXmad(Block, OpCode, ShaderOper.RR);
|
EmitXmad(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
public static void Bra(ShaderIrBlock Block, long OpCode)
|
public static void Bra(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
if ((OpCode & 0x20) != 0)
|
if ((OpCode & 0x20) != 0)
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Exit(ShaderIrBlock Block, long OpCode)
|
public static void Exit(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
int CCode = (int)OpCode & 0x1f;
|
int CCode = (int)OpCode & 0x1f;
|
||||||
|
|
||||||
|
@ -34,9 +34,34 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Kil(ShaderIrBlock Block, long OpCode)
|
public static void Kil(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Kil), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Kil), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Ssy(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
|
{
|
||||||
|
if ((OpCode & 0x20) != 0)
|
||||||
|
{
|
||||||
|
//This reads the target offset from the constant buffer.
|
||||||
|
//Almost impossible to support with GLSL.
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
||||||
|
|
||||||
|
int Target = (int)(Position + Offset);
|
||||||
|
|
||||||
|
ShaderIrOperImm Imm = new ShaderIrOperImm(Target);
|
||||||
|
|
||||||
|
Block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, Imm));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sync(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
|
{
|
||||||
|
//TODO: Implement Sync condition codes
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Sync), OpCode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -35,13 +35,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
(int)(OpCode >> 20) & 0x3fff);
|
(int)(OpCode >> 20) & 0x3fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrOperCbuf GetOperCbuf36(long OpCode)
|
|
||||||
{
|
|
||||||
return new ShaderIrOperCbuf(
|
|
||||||
(int)(OpCode >> 36) & 0x1f,
|
|
||||||
(int)(OpCode >> 22) & 0x3fff, GetOperGpr8(OpCode));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ShaderIrOperGpr GetOperGpr8(long OpCode)
|
public static ShaderIrOperGpr GetOperGpr8(long OpCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr((int)(OpCode >> 8) & 0xff);
|
return new ShaderIrOperGpr((int)(OpCode >> 8) & 0xff);
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void Ld_A(ShaderIrBlock Block, long OpCode)
|
public static void Ld_A(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
||||||
|
|
||||||
|
@ -50,8 +50,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Ld_C(ShaderIrBlock Block, long OpCode)
|
public static void Ld_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
|
int CbufPos = (int)(OpCode >> 22) & 0x3fff;
|
||||||
|
int CbufIndex = (int)(OpCode >> 36) & 0x1f;
|
||||||
int Type = (int)(OpCode >> 48) & 7;
|
int Type = (int)(OpCode >> 48) & 7;
|
||||||
|
|
||||||
if (Type > 5)
|
if (Type > 5)
|
||||||
|
@ -59,16 +61,26 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShaderIrOperGpr Temp = ShaderIrOperGpr.MakeTemporary();
|
||||||
|
|
||||||
|
Block.AddNode(new ShaderIrAsg(Temp, GetOperGpr8(OpCode)));
|
||||||
|
|
||||||
int Count = Type == 5 ? 2 : 1;
|
int Count = Type == 5 ? 2 : 1;
|
||||||
|
|
||||||
for (int Index = 0; Index < Count; Index++)
|
for (int Index = 0; Index < Count; Index++)
|
||||||
{
|
{
|
||||||
ShaderIrOperCbuf OperA = GetOperCbuf36(OpCode);
|
ShaderIrOperCbuf OperA = new ShaderIrOperCbuf(CbufIndex, CbufPos, Temp);
|
||||||
ShaderIrOperGpr OperD = GetOperGpr0 (OpCode);
|
|
||||||
|
ShaderIrOperGpr OperD = GetOperGpr0(OpCode);
|
||||||
|
|
||||||
OperA.Pos += Index;
|
OperA.Pos += Index;
|
||||||
OperD.Index += Index;
|
OperD.Index += Index;
|
||||||
|
|
||||||
|
if (!OperD.IsValidRegister)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ShaderIrNode Node = OperA;
|
ShaderIrNode Node = OperA;
|
||||||
|
|
||||||
if (Type < 4)
|
if (Type < 4)
|
||||||
|
@ -85,7 +97,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void St_A(ShaderIrBlock Block, long OpCode)
|
public static void St_A(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
||||||
|
|
||||||
|
@ -101,7 +113,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Texq(ShaderIrBlock Block, long OpCode)
|
public static void Texq(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperD = GetOperGpr0(OpCode);
|
ShaderIrNode OperD = GetOperGpr0(OpCode);
|
||||||
ShaderIrNode OperA = GetOperGpr8(OpCode);
|
ShaderIrNode OperA = GetOperGpr8(OpCode);
|
||||||
|
@ -120,12 +132,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right?
|
Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right?
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Tex(ShaderIrBlock Block, long OpCode)
|
public static void Tex(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitTex(Block, OpCode, GprHandle: false);
|
EmitTex(Block, OpCode, GprHandle: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Tex_B(ShaderIrBlock Block, long OpCode)
|
public static void Tex_B(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitTex(Block, OpCode, GprHandle: true);
|
EmitTex(Block, OpCode, GprHandle: true);
|
||||||
}
|
}
|
||||||
|
@ -190,12 +202,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Texs(ShaderIrBlock Block, long OpCode)
|
public static void Texs(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitTexs(Block, OpCode, ShaderIrInst.Texs);
|
EmitTexs(Block, OpCode, ShaderIrInst.Texs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Tlds(ShaderIrBlock Block, long OpCode)
|
public static void Tlds(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitTexs(Block, OpCode, ShaderIrInst.Txlf);
|
EmitTexs(Block, OpCode, ShaderIrInst.Txlf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,67 +25,67 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
F64 = 3
|
F64 = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2f_C(ShaderIrBlock Block, long OpCode)
|
public static void F2f_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitF2f(Block, OpCode, ShaderOper.CR);
|
EmitF2f(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2f_I(ShaderIrBlock Block, long OpCode)
|
public static void F2f_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitF2f(Block, OpCode, ShaderOper.Immf);
|
EmitF2f(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2f_R(ShaderIrBlock Block, long OpCode)
|
public static void F2f_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitF2f(Block, OpCode, ShaderOper.RR);
|
EmitF2f(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2i_C(ShaderIrBlock Block, long OpCode)
|
public static void F2i_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitF2i(Block, OpCode, ShaderOper.CR);
|
EmitF2i(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2i_I(ShaderIrBlock Block, long OpCode)
|
public static void F2i_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitF2i(Block, OpCode, ShaderOper.Immf);
|
EmitF2i(Block, OpCode, ShaderOper.Immf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void F2i_R(ShaderIrBlock Block, long OpCode)
|
public static void F2i_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitF2i(Block, OpCode, ShaderOper.RR);
|
EmitF2i(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2f_C(ShaderIrBlock Block, long OpCode)
|
public static void I2f_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.CR);
|
EmitI2f(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2f_I(ShaderIrBlock Block, long OpCode)
|
public static void I2f_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.Imm);
|
EmitI2f(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2f_R(ShaderIrBlock Block, long OpCode)
|
public static void I2f_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.RR);
|
EmitI2f(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2i_C(ShaderIrBlock Block, long OpCode)
|
public static void I2i_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitI2i(Block, OpCode, ShaderOper.CR);
|
EmitI2i(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2i_I(ShaderIrBlock Block, long OpCode)
|
public static void I2i_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitI2i(Block, OpCode, ShaderOper.Imm);
|
EmitI2i(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void I2i_R(ShaderIrBlock Block, long OpCode)
|
public static void I2i_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitI2i(Block, OpCode, ShaderOper.RR);
|
EmitI2i(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isberd(ShaderIrBlock Block, long OpCode)
|
public static void Isberd(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
//This instruction seems to be used to translate from an address to a vertex index in a GS
|
//This instruction seems to be used to translate from an address to a vertex index in a GS
|
||||||
//Stub it as such
|
//Stub it as such
|
||||||
|
@ -95,50 +95,50 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), GetOperGpr8(OpCode)), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), GetOperGpr8(OpCode)), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_C(ShaderIrBlock Block, long OpCode)
|
public static void Mov_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrOperCbuf Cbuf = GetOperCbuf34(OpCode);
|
ShaderIrOperCbuf Cbuf = GetOperCbuf34(OpCode);
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Cbuf), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Cbuf), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_I(ShaderIrBlock Block, long OpCode)
|
public static void Mov_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrOperImm Imm = GetOperImm19_20(OpCode);
|
ShaderIrOperImm Imm = GetOperImm19_20(OpCode);
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_I32(ShaderIrBlock Block, long OpCode)
|
public static void Mov_I32(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
|
ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_R(ShaderIrBlock Block, long OpCode)
|
public static void Mov_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
ShaderIrOperGpr Gpr = GetOperGpr20(OpCode);
|
ShaderIrOperGpr Gpr = GetOperGpr20(OpCode);
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sel_C(ShaderIrBlock Block, long OpCode)
|
public static void Sel_C(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitSel(Block, OpCode, ShaderOper.CR);
|
EmitSel(Block, OpCode, ShaderOper.CR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sel_I(ShaderIrBlock Block, long OpCode)
|
public static void Sel_I(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitSel(Block, OpCode, ShaderOper.Imm);
|
EmitSel(Block, OpCode, ShaderOper.Imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sel_R(ShaderIrBlock Block, long OpCode)
|
public static void Sel_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
EmitSel(Block, OpCode, ShaderOper.RR);
|
EmitSel(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov_S(ShaderIrBlock Block, long OpCode)
|
public static void Mov_S(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
Block.AddNode(new ShaderIrCmnt("Stubbed."));
|
Block.AddNode(new ShaderIrCmnt("Stubbed."));
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
public static void Out_R(ShaderIrBlock Block, long OpCode)
|
public static void Out_R(ShaderIrBlock Block, long OpCode, long Position)
|
||||||
{
|
{
|
||||||
//TODO: Those registers have to be used for something
|
//TODO: Those registers have to be used for something
|
||||||
ShaderIrOperGpr Gpr0 = GetOperGpr0(OpCode);
|
ShaderIrOperGpr Gpr0 = GetOperGpr0(OpCode);
|
||||||
|
|
|
@ -50,17 +50,29 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
ShaderIrNode LastNode = Current.GetLastNode();
|
ShaderIrNode LastNode = Current.GetLastNode();
|
||||||
|
|
||||||
ShaderIrOp Op = GetInnermostOp(LastNode);
|
ShaderIrOp InnerOp = GetInnermostOp(LastNode);
|
||||||
|
|
||||||
if (Op?.Inst == ShaderIrInst.Bra)
|
if (InnerOp?.Inst == ShaderIrInst.Bra)
|
||||||
{
|
{
|
||||||
int Offset = ((ShaderIrOperImm)Op.OperandA).Value;
|
int Offset = ((ShaderIrOperImm)InnerOp.OperandA).Value;
|
||||||
|
|
||||||
long Target = Current.EndPosition + Offset;
|
long Target = Current.EndPosition + Offset;
|
||||||
|
|
||||||
Current.Branch = Enqueue(Target, Current);
|
Current.Branch = Enqueue(Target, Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (ShaderIrNode Node in Current.Nodes)
|
||||||
|
{
|
||||||
|
if (Node is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy)
|
||||||
|
{
|
||||||
|
int Offset = ((ShaderIrOperImm)CurrOp.OperandA).Value;
|
||||||
|
|
||||||
|
long Target = Offset;
|
||||||
|
|
||||||
|
Current.Branch = Enqueue(Target, Current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (NodeHasNext(LastNode))
|
if (NodeHasNext(LastNode))
|
||||||
{
|
{
|
||||||
Current.Next = Enqueue(Current.EndPosition);
|
Current.Next = Enqueue(Current.EndPosition);
|
||||||
|
@ -157,7 +169,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
||||||
|
|
||||||
long Target = Position + Offset;
|
long Target = Position + Offset - Beginning;
|
||||||
|
|
||||||
DbgOpCode += " (0x" + Target.ToString("x16") + ")";
|
DbgOpCode += " (0x" + Target.ToString("x16") + ")";
|
||||||
}
|
}
|
||||||
|
@ -170,7 +182,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Decode(Block, OpCode);
|
Decode(Block, OpCode, Position);
|
||||||
}
|
}
|
||||||
while (!IsFlowChange(Block.GetLastNode()));
|
while (!IsFlowChange(Block.GetLastNode()));
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,30 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
|
struct OmapTarget
|
||||||
|
{
|
||||||
|
public bool Red;
|
||||||
|
public bool Green;
|
||||||
|
public bool Blue;
|
||||||
|
public bool Alpha;
|
||||||
|
|
||||||
|
public bool Enabled => Red || Green || Blue || Alpha;
|
||||||
|
|
||||||
|
public bool ComponentEnabled(int Component)
|
||||||
|
{
|
||||||
|
switch (Component)
|
||||||
|
{
|
||||||
|
case 0: return Red;
|
||||||
|
case 1: return Green;
|
||||||
|
case 2: return Blue;
|
||||||
|
case 3: return Alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(Component));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ShaderHeader
|
class ShaderHeader
|
||||||
{
|
{
|
||||||
public const int PointList = 1;
|
public const int PointList = 1;
|
||||||
|
@ -30,6 +55,10 @@
|
||||||
public int StoreReqStart { get; private set; }
|
public int StoreReqStart { get; private set; }
|
||||||
public int StoreReqEnd { get; private set; }
|
public int StoreReqEnd { get; private set; }
|
||||||
|
|
||||||
|
public OmapTarget[] OmapTargets { get; private set; }
|
||||||
|
public bool OmapSampleMask { get; private set; }
|
||||||
|
public bool OmapDepth { get; private set; }
|
||||||
|
|
||||||
public ShaderHeader(IGalMemory Memory, long Position)
|
public ShaderHeader(IGalMemory Memory, long Position)
|
||||||
{
|
{
|
||||||
uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0);
|
uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0);
|
||||||
|
@ -61,6 +90,50 @@
|
||||||
MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12);
|
MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12);
|
||||||
StoreReqStart = ReadBits(CommonWord4, 12, 8);
|
StoreReqStart = ReadBits(CommonWord4, 12, 8);
|
||||||
StoreReqEnd = ReadBits(CommonWord4, 24, 8);
|
StoreReqEnd = ReadBits(CommonWord4, 24, 8);
|
||||||
|
|
||||||
|
//Type 2 (fragment?) reading
|
||||||
|
uint Type2OmapTarget = (uint)Memory.ReadInt32(Position + 72);
|
||||||
|
uint Type2Omap = (uint)Memory.ReadInt32(Position + 76);
|
||||||
|
|
||||||
|
OmapTargets = new OmapTarget[8];
|
||||||
|
|
||||||
|
for (int i = 0; i < OmapTargets.Length; i++)
|
||||||
|
{
|
||||||
|
int Offset = i * 4;
|
||||||
|
|
||||||
|
OmapTargets[i] = new OmapTarget
|
||||||
|
{
|
||||||
|
Red = ReadBits(Type2OmapTarget, Offset + 0, 1) != 0,
|
||||||
|
Green = ReadBits(Type2OmapTarget, Offset + 1, 1) != 0,
|
||||||
|
Blue = ReadBits(Type2OmapTarget, Offset + 2, 1) != 0,
|
||||||
|
Alpha = ReadBits(Type2OmapTarget, Offset + 3, 1) != 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
OmapSampleMask = ReadBits(Type2Omap, 0, 1) != 0;
|
||||||
|
OmapDepth = ReadBits(Type2Omap, 1, 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int DepthRegister
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int Count = 0;
|
||||||
|
|
||||||
|
for (int Index = 0; Index < OmapTargets.Length; Index++)
|
||||||
|
{
|
||||||
|
for (int Component = 0; Component < 4; Component++)
|
||||||
|
{
|
||||||
|
if (OmapTargets[Index].ComponentEnabled(Component))
|
||||||
|
{
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth register is always two registers after the last color output
|
||||||
|
return Count + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ReadBits(uint Word, int Offset, int BitWidth)
|
private static int ReadBits(uint Word, int Offset, int BitWidth)
|
||||||
|
|
10
Ryujinx.Graphics/Gal/Shader/ShaderIpaMode.cs
Normal file
10
Ryujinx.Graphics/Gal/Shader/ShaderIpaMode.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
enum ShaderIpaMode
|
||||||
|
{
|
||||||
|
Pass = 0,
|
||||||
|
None = 1,
|
||||||
|
Constant = 2,
|
||||||
|
Sc = 3
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Bra,
|
Bra,
|
||||||
Exit,
|
Exit,
|
||||||
Kil,
|
Kil,
|
||||||
|
Ssy,
|
||||||
|
Sync,
|
||||||
|
|
||||||
Emit,
|
Emit,
|
||||||
Cut
|
Cut
|
||||||
|
|
12
Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs
Normal file
12
Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrMetaIpa : ShaderIrMeta
|
||||||
|
{
|
||||||
|
public ShaderIpaMode Mode { get; private set; }
|
||||||
|
|
||||||
|
public ShaderIrMetaIpa(ShaderIpaMode Mode)
|
||||||
|
{
|
||||||
|
this.Mode = Mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,11 +6,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public bool IsConst => Index == ZRIndex;
|
public bool IsConst => Index == ZRIndex;
|
||||||
|
|
||||||
|
public bool IsValidRegister => (Index <= ZRIndex);
|
||||||
|
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
|
|
||||||
public ShaderIrOperGpr(int Index)
|
public ShaderIrOperGpr(int Index)
|
||||||
{
|
{
|
||||||
this.Index = Index;
|
this.Index = Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperGpr MakeTemporary(int Index = 0)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperGpr(0x100 + Index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -112,7 +112,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("0100110000101x", ShaderDecode.Shr_C);
|
Set("0100110000101x", ShaderDecode.Shr_C);
|
||||||
Set("0011100x00101x", ShaderDecode.Shr_I);
|
Set("0011100x00101x", ShaderDecode.Shr_I);
|
||||||
Set("0101110000101x", ShaderDecode.Shr_R);
|
Set("0101110000101x", ShaderDecode.Shr_R);
|
||||||
|
Set("1110001010010x", ShaderDecode.Ssy);
|
||||||
Set("1110111111110x", ShaderDecode.St_A);
|
Set("1110111111110x", ShaderDecode.St_A);
|
||||||
|
Set("1111000011111x", ShaderDecode.Sync);
|
||||||
Set("110000xxxx111x", ShaderDecode.Tex);
|
Set("110000xxxx111x", ShaderDecode.Tex);
|
||||||
Set("1101111010111x", ShaderDecode.Tex_B);
|
Set("1101111010111x", ShaderDecode.Tex_B);
|
||||||
Set("1101111101001x", ShaderDecode.Texq);
|
Set("1101111101001x", ShaderDecode.Texq);
|
||||||
|
|
|
@ -154,16 +154,12 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
else if (IsDstFb)
|
else if (IsDstFb)
|
||||||
{
|
{
|
||||||
//Texture -> Frame Buffer copy.
|
|
||||||
const GalTextureFormat Format = GalTextureFormat.A8B8G8R8;
|
|
||||||
|
|
||||||
byte[] Buffer = TextureReader.Read(Vmm, SrcTexture());
|
byte[] Buffer = TextureReader.Read(Vmm, SrcTexture());
|
||||||
|
|
||||||
Gpu.Renderer.FrameBuffer.SetBufferData(
|
Gpu.Renderer.FrameBuffer.SetBufferData(
|
||||||
DstKey,
|
DstKey,
|
||||||
DstWidth,
|
DstWidth,
|
||||||
DstHeight,
|
DstHeight,
|
||||||
Format,
|
|
||||||
Buffer);
|
Buffer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -27,6 +27,8 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
|
|
||||||
private List<long>[] UploadedKeys;
|
private List<long>[] UploadedKeys;
|
||||||
|
|
||||||
|
private int CurrentInstance = 0;
|
||||||
|
|
||||||
public NvGpuEngine3d(NvGpu Gpu)
|
public NvGpuEngine3d(NvGpu Gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
this.Gpu = Gpu;
|
||||||
|
@ -102,7 +104,14 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
SetAlphaBlending(State);
|
SetAlphaBlending(State);
|
||||||
SetPrimitiveRestart(State);
|
SetPrimitiveRestart(State);
|
||||||
|
|
||||||
|
for (int FbIndex = 0; FbIndex < 8; FbIndex++)
|
||||||
|
{
|
||||||
SetFrameBuffer(Vmm, 0);
|
SetFrameBuffer(Vmm, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetZeta(Vmm);
|
||||||
|
|
||||||
|
SetRenderTargets();
|
||||||
|
|
||||||
long[] Keys = UploadShaders(Vmm);
|
long[] Keys = UploadShaders(Vmm);
|
||||||
|
|
||||||
|
@ -149,9 +158,11 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
int Stencil = ReadRegister(NvGpuEngine3dReg.ClearStencil);
|
int Stencil = ReadRegister(NvGpuEngine3dReg.ClearStencil);
|
||||||
|
|
||||||
SetFrameBuffer(Vmm, FbIndex);
|
SetFrameBuffer(Vmm, FbIndex);
|
||||||
|
SetZeta(Vmm);
|
||||||
|
|
||||||
Gpu.Renderer.Rasterizer.ClearBuffers(
|
Gpu.Renderer.Rasterizer.ClearBuffers(
|
||||||
Flags,
|
Flags,
|
||||||
|
FbIndex,
|
||||||
Red, Green, Blue, Alpha,
|
Red, Green, Blue, Alpha,
|
||||||
Depth,
|
Depth,
|
||||||
Stencil);
|
Stencil);
|
||||||
|
@ -161,6 +172,15 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
|
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10);
|
||||||
|
|
||||||
|
int Format = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10);
|
||||||
|
|
||||||
|
if (VA == 0 || Format == 0)
|
||||||
|
{
|
||||||
|
Gpu.Renderer.FrameBuffer.UnbindColor(FbIndex);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
long Key = Vmm.GetPhysicalAddress(VA);
|
long Key = Vmm.GetPhysicalAddress(VA);
|
||||||
|
|
||||||
FrameBuffers.Add(Key);
|
FrameBuffers.Add(Key);
|
||||||
|
@ -168,11 +188,11 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
|
int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10);
|
||||||
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
|
int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10);
|
||||||
|
|
||||||
float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 4);
|
float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 8);
|
||||||
float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 4);
|
float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 8);
|
||||||
|
|
||||||
float SX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + FbIndex * 4);
|
float SX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + FbIndex * 8);
|
||||||
float SY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + FbIndex * 4);
|
float SY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + FbIndex * 8);
|
||||||
|
|
||||||
int VpX = (int)MathF.Max(0, TX - MathF.Abs(SX));
|
int VpX = (int)MathF.Max(0, TX - MathF.Abs(SX));
|
||||||
int VpY = (int)MathF.Max(0, TY - MathF.Abs(SY));
|
int VpY = (int)MathF.Max(0, TY - MathF.Abs(SY));
|
||||||
|
@ -180,12 +200,48 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
int VpW = (int)(TX + MathF.Abs(SX)) - VpX;
|
int VpW = (int)(TX + MathF.Abs(SX)) - VpX;
|
||||||
int VpH = (int)(TY + MathF.Abs(SY)) - VpY;
|
int VpH = (int)(TY + MathF.Abs(SY)) - VpY;
|
||||||
|
|
||||||
Gpu.Renderer.FrameBuffer.Create(Key, Width, Height);
|
GalImageFormat ImageFormat = ImageFormatConverter.ConvertFrameBuffer((GalFrameBufferFormat)Format);
|
||||||
Gpu.Renderer.FrameBuffer.Bind(Key);
|
|
||||||
|
GalImage Image = new GalImage(Width, Height, ImageFormat);
|
||||||
|
|
||||||
|
long Size = TextureHelper.GetTextureSize(Image);
|
||||||
|
|
||||||
|
Gpu.Renderer.Texture.CreateFb(Key, Size, Image);
|
||||||
|
Gpu.Renderer.FrameBuffer.BindColor(Key, FbIndex);
|
||||||
|
|
||||||
Gpu.Renderer.FrameBuffer.SetViewport(VpX, VpY, VpW, VpH);
|
Gpu.Renderer.FrameBuffer.SetViewport(VpX, VpY, VpW, VpH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetZeta(NvGpuVmm Vmm)
|
||||||
|
{
|
||||||
|
long ZA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress);
|
||||||
|
|
||||||
|
int Format = ReadRegister(NvGpuEngine3dReg.ZetaFormat);
|
||||||
|
|
||||||
|
bool ZetaEnable = (ReadRegister(NvGpuEngine3dReg.ZetaEnable) & 1) != 0;
|
||||||
|
|
||||||
|
if (ZA == 0 || Format == 0 || !ZetaEnable)
|
||||||
|
{
|
||||||
|
Gpu.Renderer.FrameBuffer.UnbindZeta();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long Key = Vmm.GetPhysicalAddress(ZA);
|
||||||
|
|
||||||
|
int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz);
|
||||||
|
int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert);
|
||||||
|
|
||||||
|
GalImageFormat ImageFormat = ImageFormatConverter.ConvertZeta((GalZetaFormat)Format);
|
||||||
|
|
||||||
|
GalImage Image = new GalImage(Width, Height, ImageFormat);
|
||||||
|
|
||||||
|
long Size = TextureHelper.GetTextureSize(Image);
|
||||||
|
|
||||||
|
Gpu.Renderer.Texture.CreateFb(Key, Size, Image);
|
||||||
|
Gpu.Renderer.FrameBuffer.BindZeta(Key);
|
||||||
|
}
|
||||||
|
|
||||||
private long[] UploadShaders(NvGpuVmm Vmm)
|
private long[] UploadShaders(NvGpuVmm Vmm)
|
||||||
{
|
{
|
||||||
long[] Keys = new long[5];
|
long[] Keys = new long[5];
|
||||||
|
@ -366,6 +422,33 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetRenderTargets()
|
||||||
|
{
|
||||||
|
bool SeparateFragData = (ReadRegister(NvGpuEngine3dReg.RTSeparateFragData) & 1) != 0;
|
||||||
|
|
||||||
|
if (SeparateFragData)
|
||||||
|
{
|
||||||
|
uint Control = (uint)(ReadRegister(NvGpuEngine3dReg.RTControl));
|
||||||
|
|
||||||
|
uint Count = Control & 0xf;
|
||||||
|
|
||||||
|
int[] Map = new int[Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
int Shift = 4 + i * 3;
|
||||||
|
|
||||||
|
Map[i] = (int)((Control >> Shift) & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gpu.Renderer.FrameBuffer.SetMap(Map);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Gpu.Renderer.FrameBuffer.SetMap(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UploadTextures(NvGpuVmm Vmm, GalPipelineState State, long[] Keys)
|
private void UploadTextures(NvGpuVmm Vmm, GalPipelineState State, long[] Keys)
|
||||||
{
|
{
|
||||||
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
@ -393,8 +476,6 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
|
|
||||||
UploadTexture(Vmm, TexIndex, TextureHandle);
|
UploadTexture(Vmm, TexIndex, TextureHandle);
|
||||||
|
|
||||||
Gpu.Renderer.Shader.EnsureTextureBinding(DeclInfo.Name, TexIndex);
|
|
||||||
|
|
||||||
TexIndex++;
|
TexIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,15 +523,15 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GalTexture NewTexture = TextureFactory.MakeTexture(Vmm, TicPosition);
|
GalImage NewImage = TextureFactory.MakeTexture(Vmm, TicPosition);
|
||||||
|
|
||||||
long Size = (uint)TextureHelper.GetTextureSize(NewTexture);
|
long Size = (uint)TextureHelper.GetTextureSize(NewImage);
|
||||||
|
|
||||||
bool HasCachedTexture = false;
|
bool HasCachedTexture = false;
|
||||||
|
|
||||||
if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalTexture Texture))
|
if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Image))
|
||||||
{
|
{
|
||||||
if (NewTexture.Equals(Texture) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture))
|
if (NewImage.Equals(Image) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture))
|
||||||
{
|
{
|
||||||
Gpu.Renderer.Texture.Bind(Key, TexIndex);
|
Gpu.Renderer.Texture.Bind(Key, TexIndex);
|
||||||
|
|
||||||
|
@ -462,7 +543,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition);
|
byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition);
|
||||||
|
|
||||||
Gpu.Renderer.Texture.Create(Key, Data, NewTexture);
|
Gpu.Renderer.Texture.Create(Key, Data, NewImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Gpu.Renderer.Texture.Bind(Key, TexIndex);
|
Gpu.Renderer.Texture.Bind(Key, TexIndex);
|
||||||
|
@ -575,10 +656,25 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
|
long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
|
||||||
long VertexEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 2);
|
long VertexEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 2);
|
||||||
|
|
||||||
long VboKey = Vmm.GetPhysicalAddress(VertexPosition);
|
int VertexDivisor = ReadRegister(NvGpuEngine3dReg.VertexArrayNDivisor + Index * 4);
|
||||||
|
|
||||||
|
bool Instanced = (ReadRegister(NvGpuEngine3dReg.VertexArrayNInstance + Index) & 1) != 0;
|
||||||
|
|
||||||
int Stride = Control & 0xfff;
|
int Stride = Control & 0xfff;
|
||||||
|
|
||||||
|
if (Instanced && VertexDivisor != 0)
|
||||||
|
{
|
||||||
|
VertexPosition += Stride * (CurrentInstance / VertexDivisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VertexPosition > VertexEndPos)
|
||||||
|
{
|
||||||
|
//Instance is invalid, ignore the draw call
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
long VboKey = Vmm.GetPhysicalAddress(VertexPosition);
|
||||||
|
|
||||||
long VbSize = (VertexEndPos - VertexPosition) + 1;
|
long VbSize = (VertexEndPos - VertexPosition) + 1;
|
||||||
|
|
||||||
bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VboKey, VbSize);
|
bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VboKey, VbSize);
|
||||||
|
@ -593,6 +689,8 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
State.VertexBindings[Index].Enabled = true;
|
State.VertexBindings[Index].Enabled = true;
|
||||||
State.VertexBindings[Index].Stride = Stride;
|
State.VertexBindings[Index].Stride = Stride;
|
||||||
State.VertexBindings[Index].VboKey = VboKey;
|
State.VertexBindings[Index].VboKey = VboKey;
|
||||||
|
State.VertexBindings[Index].Instanced = Instanced;
|
||||||
|
State.VertexBindings[Index].Divisor = VertexDivisor;
|
||||||
State.VertexBindings[Index].Attribs = Attribs[Index].ToArray();
|
State.VertexBindings[Index].Attribs = Attribs[Index].ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -604,6 +702,25 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
|
|
||||||
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
|
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
|
||||||
|
|
||||||
|
bool InstanceNext = ((PrimCtrl >> 26) & 1) != 0;
|
||||||
|
bool InstanceCont = ((PrimCtrl >> 27) & 1) != 0;
|
||||||
|
|
||||||
|
if (InstanceNext && InstanceCont)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("GPU tried to increase and reset instance count at the same time");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InstanceNext)
|
||||||
|
{
|
||||||
|
CurrentInstance++;
|
||||||
|
}
|
||||||
|
else if (!InstanceCont)
|
||||||
|
{
|
||||||
|
CurrentInstance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
State.Instance = CurrentInstance;
|
||||||
|
|
||||||
Gpu.Renderer.Pipeline.Bind(State);
|
Gpu.Renderer.Pipeline.Bind(State);
|
||||||
|
|
||||||
if (IndexCount != 0)
|
if (IndexCount != 0)
|
||||||
|
@ -631,22 +748,43 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
WriteRegister(NvGpuEngine3dReg.IndexBatchCount, 0);
|
WriteRegister(NvGpuEngine3dReg.IndexBatchCount, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum QueryMode
|
||||||
|
{
|
||||||
|
WriteSeq,
|
||||||
|
Sync,
|
||||||
|
WriteCounterAndTimestamp
|
||||||
|
}
|
||||||
|
|
||||||
private void QueryControl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
private void QueryControl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
|
WriteRegister(PBEntry);
|
||||||
|
|
||||||
long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress);
|
long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress);
|
||||||
|
|
||||||
int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
|
int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
|
||||||
int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
|
int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
|
||||||
|
|
||||||
int Mode = Ctrl & 3;
|
QueryMode Mode = (QueryMode)(Ctrl & 3);
|
||||||
|
|
||||||
if (Mode == 0)
|
switch (Mode)
|
||||||
{
|
{
|
||||||
//Write mode.
|
case QueryMode.WriteSeq: Vmm.WriteInt32(Position, Seq); break;
|
||||||
Vmm.WriteInt32(Position, Seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteRegister(PBEntry);
|
case QueryMode.WriteCounterAndTimestamp:
|
||||||
|
{
|
||||||
|
//TODO: Implement counters.
|
||||||
|
long Counter = 1;
|
||||||
|
|
||||||
|
long Timestamp = (uint)Environment.TickCount;
|
||||||
|
|
||||||
|
Timestamp = (long)(Timestamp * 615384.615385);
|
||||||
|
|
||||||
|
Vmm.WriteInt64(Position + 0, Counter);
|
||||||
|
Vmm.WriteInt64(Position + 8, Timestamp);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CbData(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
private void CbData(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
|
|
|
@ -22,7 +22,16 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
StencilBackFuncRef = 0x3d5,
|
StencilBackFuncRef = 0x3d5,
|
||||||
StencilBackMask = 0x3d6,
|
StencilBackMask = 0x3d6,
|
||||||
StencilBackFuncMask = 0x3d7,
|
StencilBackFuncMask = 0x3d7,
|
||||||
|
RTSeparateFragData = 0x3eb,
|
||||||
|
ZetaAddress = 0x3f8,
|
||||||
|
ZetaFormat = 0x3fa,
|
||||||
|
ZetaBlockDimensions = 0x3fb,
|
||||||
|
ZetaLayerStride = 0x3fc,
|
||||||
VertexAttribNFormat = 0x458,
|
VertexAttribNFormat = 0x458,
|
||||||
|
RTControl = 0x487,
|
||||||
|
ZetaHoriz = 0x48a,
|
||||||
|
ZetaVert = 0x48b,
|
||||||
|
ZetaArrayMode = 0x48c,
|
||||||
DepthTestEnable = 0x4b3,
|
DepthTestEnable = 0x4b3,
|
||||||
IBlendEnable = 0x4b9,
|
IBlendEnable = 0x4b9,
|
||||||
DepthTestFunction = 0x4c3,
|
DepthTestFunction = 0x4c3,
|
||||||
|
@ -44,6 +53,8 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
StencilFrontFuncMask = 0x4e6,
|
StencilFrontFuncMask = 0x4e6,
|
||||||
StencilFrontMask = 0x4e7,
|
StencilFrontMask = 0x4e7,
|
||||||
VertexArrayElemBase = 0x50d,
|
VertexArrayElemBase = 0x50d,
|
||||||
|
VertexArrayInstBase = 0x50e,
|
||||||
|
ZetaEnable = 0x54e,
|
||||||
TexHeaderPoolOffset = 0x55d,
|
TexHeaderPoolOffset = 0x55d,
|
||||||
TexSamplerPoolOffset = 0x557,
|
TexSamplerPoolOffset = 0x557,
|
||||||
StencilTwoSideEnable = 0x565,
|
StencilTwoSideEnable = 0x565,
|
||||||
|
@ -60,6 +71,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
IndexArrayFormat = 0x5f6,
|
IndexArrayFormat = 0x5f6,
|
||||||
IndexBatchFirst = 0x5f7,
|
IndexBatchFirst = 0x5f7,
|
||||||
IndexBatchCount = 0x5f8,
|
IndexBatchCount = 0x5f8,
|
||||||
|
VertexArrayNInstance = 0x620,
|
||||||
CullFaceEnable = 0x646,
|
CullFaceEnable = 0x646,
|
||||||
FrontFace = 0x647,
|
FrontFace = 0x647,
|
||||||
CullFace = 0x648,
|
CullFace = 0x648,
|
||||||
|
|
|
@ -6,11 +6,16 @@ namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
static class TextureFactory
|
static class TextureFactory
|
||||||
{
|
{
|
||||||
public static GalTexture MakeTexture(NvGpuVmm Vmm, long TicPosition)
|
public static GalImage MakeTexture(NvGpuVmm Vmm, long TicPosition)
|
||||||
{
|
{
|
||||||
int[] Tic = ReadWords(Vmm, TicPosition, 8);
|
int[] Tic = ReadWords(Vmm, TicPosition, 8);
|
||||||
|
|
||||||
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
|
GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7);
|
||||||
|
GalTextureType GType = (GalTextureType)((Tic[0] >> 10) & 7);
|
||||||
|
GalTextureType BType = (GalTextureType)((Tic[0] >> 13) & 7);
|
||||||
|
GalTextureType AType = (GalTextureType)((Tic[0] >> 16) & 7);
|
||||||
|
|
||||||
|
GalImageFormat Format = ImageFormatConverter.ConvertTexture((GalTextureFormat)(Tic[0] & 0x7f), RType, GType, BType, AType);
|
||||||
|
|
||||||
GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7);
|
GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7);
|
||||||
GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7);
|
GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7);
|
||||||
|
@ -20,7 +25,7 @@ namespace Ryujinx.HLE.Gpu.Texture
|
||||||
int Width = (Tic[4] & 0xffff) + 1;
|
int Width = (Tic[4] & 0xffff) + 1;
|
||||||
int Height = (Tic[5] & 0xffff) + 1;
|
int Height = (Tic[5] & 0xffff) + 1;
|
||||||
|
|
||||||
return new GalTexture(
|
return new GalImage(
|
||||||
Width,
|
Width,
|
||||||
Height,
|
Height,
|
||||||
Format,
|
Format,
|
||||||
|
|
|
@ -30,117 +30,155 @@ namespace Ryujinx.HLE.Gpu.Texture
|
||||||
throw new NotImplementedException(Texture.Swizzle.ToString());
|
throw new NotImplementedException(Texture.Swizzle.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetTextureSize(GalTexture Texture)
|
public static int GetTextureSize(GalImage Image)
|
||||||
{
|
{
|
||||||
switch (Texture.Format)
|
switch (Image.Format)
|
||||||
{
|
{
|
||||||
case GalTextureFormat.R32G32B32A32:
|
case GalImageFormat.R32G32B32A32_SFLOAT:
|
||||||
return Texture.Width * Texture.Height * 16;
|
case GalImageFormat.R32G32B32A32_SINT:
|
||||||
|
case GalImageFormat.R32G32B32A32_UINT:
|
||||||
|
return Image.Width * Image.Height * 16;
|
||||||
|
|
||||||
case GalTextureFormat.R16G16B16A16:
|
case GalImageFormat.R16G16B16A16_SFLOAT:
|
||||||
return Texture.Width * Texture.Height * 8;
|
case GalImageFormat.R16G16B16A16_SINT:
|
||||||
|
case GalImageFormat.R16G16B16A16_SNORM:
|
||||||
|
case GalImageFormat.R16G16B16A16_UINT:
|
||||||
|
case GalImageFormat.R16G16B16A16_UNORM:
|
||||||
|
case GalImageFormat.D32_SFLOAT_S8_UINT:
|
||||||
|
case GalImageFormat.R32G32_SFLOAT:
|
||||||
|
case GalImageFormat.R32G32_SINT:
|
||||||
|
case GalImageFormat.R32G32_UINT:
|
||||||
|
return Image.Width * Image.Height * 8;
|
||||||
|
|
||||||
case GalTextureFormat.A8B8G8R8:
|
case GalImageFormat.A8B8G8R8_SINT_PACK32:
|
||||||
case GalTextureFormat.A2B10G10R10:
|
case GalImageFormat.A8B8G8R8_SNORM_PACK32:
|
||||||
case GalTextureFormat.R32:
|
case GalImageFormat.A8B8G8R8_UINT_PACK32:
|
||||||
case GalTextureFormat.ZF32:
|
case GalImageFormat.A8B8G8R8_UNORM_PACK32:
|
||||||
case GalTextureFormat.BF10GF11RF11:
|
case GalImageFormat.A8B8G8R8_SRGB_PACK32:
|
||||||
case GalTextureFormat.Z24S8:
|
case GalImageFormat.A2B10G10R10_SINT_PACK32:
|
||||||
return Texture.Width * Texture.Height * 4;
|
case GalImageFormat.A2B10G10R10_SNORM_PACK32:
|
||||||
|
case GalImageFormat.A2B10G10R10_UINT_PACK32:
|
||||||
|
case GalImageFormat.A2B10G10R10_UNORM_PACK32:
|
||||||
|
case GalImageFormat.R16G16_SFLOAT:
|
||||||
|
case GalImageFormat.R16G16_SINT:
|
||||||
|
case GalImageFormat.R16G16_SNORM:
|
||||||
|
case GalImageFormat.R16G16_UINT:
|
||||||
|
case GalImageFormat.R16G16_UNORM:
|
||||||
|
case GalImageFormat.R32_SFLOAT:
|
||||||
|
case GalImageFormat.R32_SINT:
|
||||||
|
case GalImageFormat.R32_UINT:
|
||||||
|
case GalImageFormat.D32_SFLOAT:
|
||||||
|
case GalImageFormat.B10G11R11_UFLOAT_PACK32:
|
||||||
|
case GalImageFormat.D24_UNORM_S8_UINT:
|
||||||
|
return Image.Width * Image.Height * 4;
|
||||||
|
|
||||||
case GalTextureFormat.A1B5G5R5:
|
case GalImageFormat.B4G4R4A4_UNORM_PACK16:
|
||||||
case GalTextureFormat.B5G6R5:
|
case GalImageFormat.A1R5G5B5_UNORM_PACK16:
|
||||||
case GalTextureFormat.G8R8:
|
case GalImageFormat.B5G6R5_UNORM_PACK16:
|
||||||
case GalTextureFormat.R16:
|
case GalImageFormat.R8G8_SINT:
|
||||||
return Texture.Width * Texture.Height * 2;
|
case GalImageFormat.R8G8_SNORM:
|
||||||
|
case GalImageFormat.R8G8_UINT:
|
||||||
|
case GalImageFormat.R8G8_UNORM:
|
||||||
|
case GalImageFormat.R16_SFLOAT:
|
||||||
|
case GalImageFormat.R16_SINT:
|
||||||
|
case GalImageFormat.R16_SNORM:
|
||||||
|
case GalImageFormat.R16_UINT:
|
||||||
|
case GalImageFormat.R16_UNORM:
|
||||||
|
case GalImageFormat.D16_UNORM:
|
||||||
|
return Image.Width * Image.Height * 2;
|
||||||
|
|
||||||
case GalTextureFormat.R8:
|
case GalImageFormat.R8_SINT:
|
||||||
return Texture.Width * Texture.Height;
|
case GalImageFormat.R8_SNORM:
|
||||||
|
case GalImageFormat.R8_UINT:
|
||||||
|
case GalImageFormat.R8_UNORM:
|
||||||
|
return Image.Width * Image.Height;
|
||||||
|
|
||||||
case GalTextureFormat.BC1:
|
case GalImageFormat.BC1_RGBA_UNORM_BLOCK:
|
||||||
case GalTextureFormat.BC4:
|
case GalImageFormat.BC4_SNORM_BLOCK:
|
||||||
|
case GalImageFormat.BC4_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 4, 4, 8);
|
return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.BC6H_SF16:
|
case GalImageFormat.BC6H_SFLOAT_BLOCK:
|
||||||
case GalTextureFormat.BC6H_UF16:
|
case GalImageFormat.BC6H_UFLOAT_BLOCK:
|
||||||
case GalTextureFormat.BC7U:
|
case GalImageFormat.BC7_UNORM_BLOCK:
|
||||||
case GalTextureFormat.BC2:
|
case GalImageFormat.BC2_UNORM_BLOCK:
|
||||||
case GalTextureFormat.BC3:
|
case GalImageFormat.BC3_UNORM_BLOCK:
|
||||||
case GalTextureFormat.BC5:
|
case GalImageFormat.BC5_SNORM_BLOCK:
|
||||||
case GalTextureFormat.Astc2D4x4:
|
case GalImageFormat.BC5_UNORM_BLOCK:
|
||||||
|
case GalImageFormat.ASTC_4x4_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 4, 4, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 4, 4, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D5x5:
|
case GalImageFormat.ASTC_5x5_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 5, 5, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 5, 5, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D6x6:
|
case GalImageFormat.ASTC_6x6_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 6, 6, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 6, 6, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D8x8:
|
case GalImageFormat.ASTC_8x8_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 8, 8, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 8, 8, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D10x10:
|
case GalImageFormat.ASTC_10x10_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 10, 10, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 10, 10, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D12x12:
|
case GalImageFormat.ASTC_12x12_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 12, 12, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 12, 12, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D5x4:
|
case GalImageFormat.ASTC_5x4_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 5, 4, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 5, 4, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D6x5:
|
case GalImageFormat.ASTC_6x5_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 6, 5, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 6, 5, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D8x6:
|
case GalImageFormat.ASTC_8x6_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 8, 6, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 8, 6, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D10x8:
|
case GalImageFormat.ASTC_10x8_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 10, 8, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 10, 8, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D12x10:
|
case GalImageFormat.ASTC_12x10_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 12, 10, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 12, 10, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D8x5:
|
case GalImageFormat.ASTC_8x5_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 8, 5, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 8, 5, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D10x5:
|
case GalImageFormat.ASTC_10x5_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 10, 5, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 10, 5, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
case GalTextureFormat.Astc2D10x6:
|
case GalImageFormat.ASTC_10x6_UNORM_BLOCK:
|
||||||
{
|
{
|
||||||
return CompressedTextureSize(Texture.Width, Texture.Height, 10, 6, 16);
|
return CompressedTextureSize(Image.Width, Image.Height, 10, 6, 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException("0x" + Texture.Format.ToString("x2"));
|
throw new NotImplementedException(Image.Format.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int CompressedTextureSize(int TextureWidth, int TextureHeight, int BlockWidth, int BlockHeight, int Bpb)
|
public static int CompressedTextureSize(int TextureWidth, int TextureHeight, int BlockWidth, int BlockHeight, int Bpb)
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
case GalTextureFormat.R32G32B32A32: return Read16Bpp (Memory, Texture);
|
case GalTextureFormat.R32G32B32A32: return Read16Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.R16G16B16A16: return Read8Bpp (Memory, Texture);
|
case GalTextureFormat.R16G16B16A16: return Read8Bpp (Memory, Texture);
|
||||||
|
case GalTextureFormat.R32G32: return Read8Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.A8B8G8R8: return Read4Bpp (Memory, Texture);
|
case GalTextureFormat.A8B8G8R8: return Read4Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.A2B10G10R10: return Read4Bpp (Memory, Texture);
|
case GalTextureFormat.A2B10G10R10: return Read4Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.R32: return Read4Bpp (Memory, Texture);
|
case GalTextureFormat.R32: return Read4Bpp (Memory, Texture);
|
||||||
|
@ -19,6 +20,7 @@ namespace Ryujinx.HLE.Gpu.Texture
|
||||||
case GalTextureFormat.Z24S8: return Read4Bpp (Memory, Texture);
|
case GalTextureFormat.Z24S8: return Read4Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.A1B5G5R5: return Read5551 (Memory, Texture);
|
case GalTextureFormat.A1B5G5R5: return Read5551 (Memory, Texture);
|
||||||
case GalTextureFormat.B5G6R5: return Read565 (Memory, Texture);
|
case GalTextureFormat.B5G6R5: return Read565 (Memory, Texture);
|
||||||
|
case GalTextureFormat.A4B4G4R4: return Read2Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.G8R8: return Read2Bpp (Memory, Texture);
|
case GalTextureFormat.G8R8: return Read2Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.R16: return Read2Bpp (Memory, Texture);
|
case GalTextureFormat.R16: return Read2Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.R8: return Read1Bpp (Memory, Texture);
|
case GalTextureFormat.R8: return Read1Bpp (Memory, Texture);
|
||||||
|
@ -31,6 +33,7 @@ namespace Ryujinx.HLE.Gpu.Texture
|
||||||
case GalTextureFormat.BC4: return Read8Bpt4x4 (Memory, Texture);
|
case GalTextureFormat.BC4: return Read8Bpt4x4 (Memory, Texture);
|
||||||
case GalTextureFormat.BC5: return Read16BptCompressedTexture(Memory, Texture, 4, 4);
|
case GalTextureFormat.BC5: return Read16BptCompressedTexture(Memory, Texture, 4, 4);
|
||||||
case GalTextureFormat.ZF32: return Read4Bpp (Memory, Texture);
|
case GalTextureFormat.ZF32: return Read4Bpp (Memory, Texture);
|
||||||
|
case GalTextureFormat.ZF32_X24S8: return Read8Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.Astc2D4x4: return Read16BptCompressedTexture(Memory, Texture, 4, 4);
|
case GalTextureFormat.Astc2D4x4: return Read16BptCompressedTexture(Memory, Texture, 4, 4);
|
||||||
case GalTextureFormat.Astc2D5x5: return Read16BptCompressedTexture(Memory, Texture, 5, 5);
|
case GalTextureFormat.Astc2D5x5: return Read16BptCompressedTexture(Memory, Texture, 5, 5);
|
||||||
case GalTextureFormat.Astc2D6x6: return Read16BptCompressedTexture(Memory, Texture, 6, 6);
|
case GalTextureFormat.Astc2D6x6: return Read16BptCompressedTexture(Memory, Texture, 6, 6);
|
||||||
|
@ -47,7 +50,7 @@ namespace Ryujinx.HLE.Gpu.Texture
|
||||||
case GalTextureFormat.Astc2D10x6: return Read16BptCompressedTexture(Memory, Texture, 10, 6);
|
case GalTextureFormat.Astc2D10x6: return Read16BptCompressedTexture(Memory, Texture, 10, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException("0x" + Texture.Format.ToString("x2"));
|
throw new NotImplementedException("0x" + ((int)Texture.Format).ToString("x2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe static byte[] Read1Bpp(IAMemory Memory, TextureInfo Texture)
|
private unsafe static byte[] Read1Bpp(IAMemory Memory, TextureInfo Texture)
|
||||||
|
|
|
@ -174,39 +174,39 @@ namespace Ryujinx.HLE.HOS.Ipc
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (long Position, long Size) GetBufferType0x21()
|
public (long Position, long Size) GetBufferType0x21(int Index = 0)
|
||||||
{
|
{
|
||||||
if (PtrBuff.Count != 0 &&
|
if (PtrBuff.Count > Index &&
|
||||||
PtrBuff[0].Position != 0 &&
|
PtrBuff[Index].Position != 0 &&
|
||||||
PtrBuff[0].Size != 0)
|
PtrBuff[Index].Size != 0)
|
||||||
{
|
{
|
||||||
return (PtrBuff[0].Position, PtrBuff[0].Size);
|
return (PtrBuff[Index].Position, PtrBuff[Index].Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SendBuff.Count != 0 &&
|
if (SendBuff.Count > Index &&
|
||||||
SendBuff[0].Position != 0 &&
|
SendBuff[Index].Position != 0 &&
|
||||||
SendBuff[0].Size != 0)
|
SendBuff[Index].Size != 0)
|
||||||
{
|
{
|
||||||
return (SendBuff[0].Position, SendBuff[0].Size);
|
return (SendBuff[Index].Position, SendBuff[Index].Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0, 0);
|
return (0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public (long Position, long Size) GetBufferType0x22()
|
public (long Position, long Size) GetBufferType0x22(int Index = 0)
|
||||||
{
|
{
|
||||||
if (RecvListBuff.Count != 0 &&
|
if (RecvListBuff.Count > Index &&
|
||||||
RecvListBuff[0].Position != 0 &&
|
RecvListBuff[Index].Position != 0 &&
|
||||||
RecvListBuff[0].Size != 0)
|
RecvListBuff[Index].Size != 0)
|
||||||
{
|
{
|
||||||
return (RecvListBuff[0].Position, RecvListBuff[0].Size);
|
return (RecvListBuff[Index].Position, RecvListBuff[Index].Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReceiveBuff.Count != 0 &&
|
if (ReceiveBuff.Count > Index &&
|
||||||
ReceiveBuff[0].Position != 0 &&
|
ReceiveBuff[Index].Position != 0 &&
|
||||||
ReceiveBuff[0].Size != 0)
|
ReceiveBuff[Index].Size != 0)
|
||||||
{
|
{
|
||||||
return (ReceiveBuff[0].Position, ReceiveBuff[0].Size);
|
return (ReceiveBuff[Index].Position, ReceiveBuff[Index].Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0, 0);
|
return (0, 0);
|
||||||
|
|
|
@ -9,9 +9,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
{
|
{
|
||||||
private void SvcSetHeapSize(AThreadState ThreadState)
|
private void SvcSetHeapSize(AThreadState ThreadState)
|
||||||
{
|
{
|
||||||
long Size = (long)ThreadState.X1;
|
ulong Size = ThreadState.X1;
|
||||||
|
|
||||||
if ((Size & 0x1fffff) != 0 || Size != (uint)Size)
|
if ((Size & 0xFFFFFFFE001FFFFF) != 0)
|
||||||
{
|
{
|
||||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{Size:x16} is not aligned!");
|
Device.Log.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{Size:x16} is not aligned!");
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Result = Process.MemoryManager.TrySetHeapSize(Size, out long Position);
|
long Result = Process.MemoryManager.TrySetHeapSize((long)Size, out long Position);
|
||||||
|
|
||||||
ThreadState.X0 = (ulong)Result;
|
ThreadState.X0 = (ulong)Result;
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,13 @@ using static Ryujinx.HLE.HOS.ErrorCode;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Acc
|
namespace Ryujinx.HLE.HOS.Services.Acc
|
||||||
{
|
{
|
||||||
class IAccountServiceForApplication : IpcService
|
class IAccountService : IpcService
|
||||||
{
|
{
|
||||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||||
|
|
||||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||||
|
|
||||||
public IAccountServiceForApplication()
|
public IAccountService()
|
||||||
{
|
{
|
||||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
{
|
{
|
|
@ -3,7 +3,10 @@ using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.SystemState;
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
using Ryujinx.HLE.Logging;
|
using Ryujinx.HLE.Logging;
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.Utilities;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Acc
|
namespace Ryujinx.HLE.HOS.Services.Acc
|
||||||
|
@ -16,15 +19,21 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
||||||
|
|
||||||
private UserProfile Profile;
|
private UserProfile Profile;
|
||||||
|
|
||||||
|
private Stream ProfilePictureStream;
|
||||||
|
|
||||||
public IProfile(UserProfile Profile)
|
public IProfile(UserProfile Profile)
|
||||||
{
|
{
|
||||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
{
|
{
|
||||||
{ 0, Get },
|
{ 0, Get },
|
||||||
{ 1, GetBase }
|
{ 1, GetBase },
|
||||||
|
{ 10, GetImageSize },
|
||||||
|
{ 11, LoadImage },
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Profile = Profile;
|
this.Profile = Profile;
|
||||||
|
|
||||||
|
ProfilePictureStream = Assembly.GetCallingAssembly().GetManifestResourceStream("Ryujinx.HLE.RyujinxProfileImage.jpg");
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Get(ServiceCtx Context)
|
public long Get(ServiceCtx Context)
|
||||||
|
@ -54,5 +63,28 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long LoadImage(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
long BufferPosition = Context.Request.ReceiveBuff[0].Position;
|
||||||
|
long BufferLen = Context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
|
byte[] ProfilePictureData = new byte[BufferLen];
|
||||||
|
|
||||||
|
ProfilePictureStream.Read(ProfilePictureData, 0, ProfilePictureData.Length);
|
||||||
|
|
||||||
|
Context.Memory.WriteBytes(BufferPosition, ProfilePictureData);
|
||||||
|
|
||||||
|
Context.ResponseData.Write(ProfilePictureStream.Length);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long GetImageSize(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
Context.ResponseData.Write(ProfilePictureStream.Length);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,6 +32,8 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
{ 14, Connect },
|
{ 14, Connect },
|
||||||
{ 18, Listen },
|
{ 18, Listen },
|
||||||
{ 21, SetSockOpt },
|
{ 21, SetSockOpt },
|
||||||
|
{ 24, Write },
|
||||||
|
{ 25, Read },
|
||||||
{ 26, Close }
|
{ 26, Close }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -122,15 +124,15 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
int SocketId = Context.RequestData.ReadInt32();
|
int SocketId = Context.RequestData.ReadInt32();
|
||||||
int SocketFlags = Context.RequestData.ReadInt32();
|
int SocketFlags = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
byte[] ReceivedBuffer = new byte[Context.Request.ReceiveBuff[0].Size];
|
(long ReceivePosition, long ReceiveLength) = Context.Request.GetBufferType0x22();
|
||||||
|
|
||||||
|
byte[] ReceivedBuffer = new byte[ReceiveLength];
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int BytesRead = Sockets[SocketId].Handle.Receive(ReceivedBuffer);
|
int BytesRead = Sockets[SocketId].Handle.Receive(ReceivedBuffer);
|
||||||
|
|
||||||
//Logging.Debug("Received Buffer:" + Environment.NewLine + Logging.HexDump(ReceivedBuffer));
|
Context.Memory.WriteBytes(ReceivePosition, ReceivedBuffer);
|
||||||
|
|
||||||
Context.Memory.WriteBytes(Context.Request.ReceiveBuff[0].Position, ReceivedBuffer);
|
|
||||||
|
|
||||||
Context.ResponseData.Write(BytesRead);
|
Context.ResponseData.Write(BytesRead);
|
||||||
Context.ResponseData.Write(0);
|
Context.ResponseData.Write(0);
|
||||||
|
@ -150,13 +152,12 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
int SocketId = Context.RequestData.ReadInt32();
|
int SocketId = Context.RequestData.ReadInt32();
|
||||||
int SocketFlags = Context.RequestData.ReadInt32();
|
int SocketFlags = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
byte[] SentBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position,
|
(long SentPosition, long SentSize) = Context.Request.GetBufferType0x21();
|
||||||
Context.Request.SendBuff[0].Size);
|
|
||||||
|
byte[] SentBuffer = Context.Memory.ReadBytes(SentPosition, SentSize);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Logging.Debug("Sent Buffer:" + Environment.NewLine + Logging.HexDump(SentBuffer));
|
|
||||||
|
|
||||||
int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer);
|
int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer);
|
||||||
|
|
||||||
Context.ResponseData.Write(BytesSent);
|
Context.ResponseData.Write(BytesSent);
|
||||||
|
@ -180,8 +181,9 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
byte[] SentBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position,
|
byte[] SentBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position,
|
||||||
Context.Request.SendBuff[0].Size);
|
Context.Request.SendBuff[0].Size);
|
||||||
|
|
||||||
byte[] AddressBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[1].Position,
|
(long AddressPosition, long AddressSize) = Context.Request.GetBufferType0x21(Index: 1);
|
||||||
Context.Request.SendBuff[1].Size);
|
|
||||||
|
byte[] AddressBuffer = Context.Memory.ReadBytes(AddressPosition, AddressSize);
|
||||||
|
|
||||||
if (!Sockets[SocketId].Handle.Connected)
|
if (!Sockets[SocketId].Handle.Connected)
|
||||||
{
|
{
|
||||||
|
@ -200,8 +202,6 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Logging.Debug("Sent Buffer:" + Environment.NewLine + Logging.HexDump(SentBuffer));
|
|
||||||
|
|
||||||
int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer);
|
int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer);
|
||||||
|
|
||||||
Context.ResponseData.Write(BytesSent);
|
Context.ResponseData.Write(BytesSent);
|
||||||
|
@ -221,7 +221,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
{
|
{
|
||||||
int SocketId = Context.RequestData.ReadInt32();
|
int SocketId = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
long AddrBufferPtr = Context.Request.ReceiveBuff[0].Position;
|
(long AddrBufferPosition, long AddrBuffSize) = Context.Request.GetBufferType0x22();
|
||||||
|
|
||||||
Socket HandleAccept = null;
|
Socket HandleAccept = null;
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
|
|
||||||
Writer.Write(IpAddress);
|
Writer.Write(IpAddress);
|
||||||
|
|
||||||
Context.Memory.WriteBytes(AddrBufferPtr, MS.ToArray());
|
Context.Memory.WriteBytes(AddrBufferPosition, MS.ToArray());
|
||||||
|
|
||||||
Context.ResponseData.Write(Sockets.Count - 1);
|
Context.ResponseData.Write(Sockets.Count - 1);
|
||||||
Context.ResponseData.Write(0);
|
Context.ResponseData.Write(0);
|
||||||
|
@ -286,8 +286,9 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
{
|
{
|
||||||
int SocketId = Context.RequestData.ReadInt32();
|
int SocketId = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
byte[] AddressBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position,
|
(long AddressPosition, long AddressSize) = Context.Request.GetBufferType0x21();
|
||||||
Context.Request.SendBuff[0].Size);
|
|
||||||
|
byte[] AddressBuffer = Context.Memory.ReadBytes(AddressPosition, AddressSize);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -310,8 +311,9 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
{
|
{
|
||||||
int SocketId = Context.RequestData.ReadInt32();
|
int SocketId = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
byte[] AddressBuffer = Context.Memory.ReadBytes(Context.Request.SendBuff[0].Position,
|
(long AddressPosition, long AddressSize) = Context.Request.GetBufferType0x21();
|
||||||
Context.Request.SendBuff[0].Size);
|
|
||||||
|
byte[] AddressBuffer = Context.Memory.ReadBytes(AddressPosition, AddressSize);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -383,6 +385,60 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//(u32 socket, buffer<i8, 0x21, 0> message) -> (i32 ret, u32 bsd_errno)
|
||||||
|
public long Write(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
int SocketId = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
|
(long SentPosition, long SentSize) = Context.Request.GetBufferType0x21();
|
||||||
|
|
||||||
|
byte[] SentBuffer = Context.Memory.ReadBytes(SentPosition, SentSize);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Logging.Debug("Wrote Buffer:" + Environment.NewLine + Logging.HexDump(SentBuffer));
|
||||||
|
|
||||||
|
int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer);
|
||||||
|
|
||||||
|
Context.ResponseData.Write(BytesSent);
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
}
|
||||||
|
catch (SocketException Ex)
|
||||||
|
{
|
||||||
|
Context.ResponseData.Write(-1);
|
||||||
|
Context.ResponseData.Write(Ex.ErrorCode - 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//(u32 socket) -> (i32 ret, u32 bsd_errno, buffer<i8, 0x22, 0> message)
|
||||||
|
public long Read(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
int SocketId = Context.RequestData.ReadInt32();
|
||||||
|
|
||||||
|
(long ReceivePosition, long ReceiveLength) = Context.Request.GetBufferType0x22();
|
||||||
|
|
||||||
|
byte[] ReceivedBuffer = new byte[ReceiveLength];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int BytesRead = Sockets[SocketId].Handle.Receive(ReceivedBuffer);
|
||||||
|
|
||||||
|
Context.Memory.WriteBytes(ReceivePosition, ReceivedBuffer);
|
||||||
|
|
||||||
|
Context.ResponseData.Write(BytesRead);
|
||||||
|
Context.ResponseData.Write(0);
|
||||||
|
}
|
||||||
|
catch (SocketException Ex)
|
||||||
|
{
|
||||||
|
Context.ResponseData.Write(-1);
|
||||||
|
Context.ResponseData.Write(Ex.ErrorCode - 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//(u32 socket) -> (i32 ret, u32 bsd_errno)
|
//(u32 socket) -> (i32 ret, u32 bsd_errno)
|
||||||
public long Close(ServiceCtx Context)
|
public long Close(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
|
@ -413,7 +469,7 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
|
|
||||||
int Size = Reader.ReadByte();
|
int Size = Reader.ReadByte();
|
||||||
int Family = Reader.ReadByte();
|
int Family = Reader.ReadByte();
|
||||||
int Port = EndianSwap.Swap16(Reader.ReadInt16());
|
int Port = EndianSwap.Swap16(Reader.ReadUInt16());
|
||||||
|
|
||||||
string IpAddress = Reader.ReadByte().ToString() + "." +
|
string IpAddress = Reader.ReadByte().ToString() + "." +
|
||||||
Reader.ReadByte().ToString() + "." +
|
Reader.ReadByte().ToString() + "." +
|
||||||
|
@ -421,7 +477,6 @@ namespace Ryujinx.HLE.HOS.Services.Bsd
|
||||||
Reader.ReadByte().ToString();
|
Reader.ReadByte().ToString();
|
||||||
|
|
||||||
Sockets[SocketId].IpAddress = IPAddress.Parse(IpAddress);
|
Sockets[SocketId].IpAddress = IPAddress.Parse(IpAddress);
|
||||||
|
|
||||||
Sockets[SocketId].RemoteEP = new IPEndPoint(Sockets[SocketId].IpAddress, Port);
|
Sockets[SocketId].RemoteEP = new IPEndPoint(Sockets[SocketId].IpAddress, Port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,9 @@ namespace Ryujinx.HLE.HOS.Services.Lm
|
||||||
|
|
||||||
public long Log(ServiceCtx Context)
|
public long Log(ServiceCtx Context)
|
||||||
{
|
{
|
||||||
byte[] LogBuffer = Context.Memory.ReadBytes(
|
|
||||||
Context.Request.PtrBuff[0].Position,
|
(long BufPos, long BufSize) = Context.Request.GetBufferType0x21();
|
||||||
Context.Request.PtrBuff[0].Size);
|
byte[] LogBuffer = Context.Memory.ReadBytes(BufPos, BufSize);
|
||||||
|
|
||||||
using (MemoryStream MS = new MemoryStream(LogBuffer))
|
using (MemoryStream MS = new MemoryStream(LogBuffer))
|
||||||
{
|
{
|
||||||
|
@ -50,20 +50,36 @@ namespace Ryujinx.HLE.HOS.Services.Lm
|
||||||
|
|
||||||
string FieldStr = string.Empty;
|
string FieldStr = string.Empty;
|
||||||
|
|
||||||
if (Field == LmLogField.Skip)
|
if (Field == LmLogField.Start)
|
||||||
{
|
{
|
||||||
Reader.ReadByte();
|
Reader.ReadBytes(Size);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (Field == LmLogField.Stop)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
else if (Field == LmLogField.Line)
|
else if (Field == LmLogField.Line)
|
||||||
{
|
{
|
||||||
FieldStr = Field + ": " + Reader.ReadInt32();
|
FieldStr = Field + ": " + Reader.ReadInt32();
|
||||||
}
|
}
|
||||||
else
|
else if (Field == LmLogField.DropCount)
|
||||||
|
{
|
||||||
|
FieldStr = Field + ": " + Reader.ReadInt64();
|
||||||
|
}
|
||||||
|
else if (Field == LmLogField.Time)
|
||||||
|
{
|
||||||
|
FieldStr = Field + ": " + Reader.ReadInt64() + "s";
|
||||||
|
}
|
||||||
|
else if (Field < LmLogField.Count)
|
||||||
{
|
{
|
||||||
FieldStr = Field + ": \"" + Encoding.UTF8.GetString(Reader.ReadBytes(Size)) + "\"";
|
FieldStr = Field + ": \"" + Encoding.UTF8.GetString(Reader.ReadBytes(Size)) + "\"";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FieldStr = "Field" + Field + ": \"" + Encoding.UTF8.GetString(Reader.ReadBytes(Size)) + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
SB.AppendLine(" " + FieldStr);
|
SB.AppendLine(" " + FieldStr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,17 @@ namespace Ryujinx.HLE.HOS.Services.Lm
|
||||||
{
|
{
|
||||||
enum LmLogField
|
enum LmLogField
|
||||||
{
|
{
|
||||||
Skip = 1,
|
Start = 0,
|
||||||
|
Stop = 1,
|
||||||
Message = 2,
|
Message = 2,
|
||||||
Line = 3,
|
Line = 3,
|
||||||
Filename = 4,
|
Filename = 4,
|
||||||
Function = 5,
|
Function = 5,
|
||||||
Module = 6,
|
Module = 6,
|
||||||
Thread = 7
|
Thread = 7,
|
||||||
|
DropCount = 8,
|
||||||
|
Time = 9,
|
||||||
|
ProgramName = 10,
|
||||||
|
Count
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -187,9 +187,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvGpuAS
|
||||||
{
|
{
|
||||||
Left = Middle + 1;
|
Left = Middle + 1;
|
||||||
|
|
||||||
|
if ((ulong)Position > Rg.Start)
|
||||||
|
{
|
||||||
LtRg = Rg;
|
LtRg = Rg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return LtRg;
|
return LtRg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,10 @@ namespace Ryujinx.HLE.HOS.Services
|
||||||
switch (Name)
|
switch (Name)
|
||||||
{
|
{
|
||||||
case "acc:u0":
|
case "acc:u0":
|
||||||
return new IAccountServiceForApplication();
|
return new IAccountService();
|
||||||
|
|
||||||
|
case "acc:u1":
|
||||||
|
return new IAccountService();
|
||||||
|
|
||||||
case "aoc:u":
|
case "aoc:u":
|
||||||
return new IAddOnContentManager();
|
return new IAddOnContentManager();
|
||||||
|
|
|
@ -13,6 +13,14 @@
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="RyujinxProfileImage.jpg" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="RyujinxProfileImage.jpg" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
||||||
|
|
BIN
Ryujinx.HLE/RyujinxProfileImage.jpg
Normal file
BIN
Ryujinx.HLE/RyujinxProfileImage.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
static class EndianSwap
|
static class EndianSwap
|
||||||
{
|
{
|
||||||
public static short Swap16(short Value) => (short)(((Value >> 8) & 0xff) | (Value << 8));
|
public static ushort Swap16(ushort Value) => (ushort)(((Value >> 8) & 0xff) | (Value << 8));
|
||||||
|
|
||||||
public static int Swap32(int Value)
|
public static int Swap32(int Value)
|
||||||
{
|
{
|
||||||
|
|
28
Ryujinx.Tests.Unicorn/IndexedProperty.cs
Normal file
28
Ryujinx.Tests.Unicorn/IndexedProperty.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn
|
||||||
|
{
|
||||||
|
public class IndexedProperty<TIndex, TValue>
|
||||||
|
{
|
||||||
|
readonly Action<TIndex, TValue> SetAction;
|
||||||
|
readonly Func<TIndex, TValue> GetFunc;
|
||||||
|
|
||||||
|
public IndexedProperty(Func<TIndex, TValue> getFunc, Action<TIndex, TValue> setAction)
|
||||||
|
{
|
||||||
|
this.GetFunc = getFunc;
|
||||||
|
this.SetAction = setAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue this[TIndex i]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetFunc(i);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetAction(i, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Ryujinx.Tests.Unicorn/MemoryPermission.cs
Normal file
13
Ryujinx.Tests.Unicorn/MemoryPermission.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn
|
||||||
|
{
|
||||||
|
public enum MemoryPermission
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
READ = 1,
|
||||||
|
WRITE = 2,
|
||||||
|
EXEC = 4,
|
||||||
|
ALL = 7,
|
||||||
|
}
|
||||||
|
}
|
296
Ryujinx.Tests.Unicorn/Native/ArmRegister.cs
Normal file
296
Ryujinx.Tests.Unicorn/Native/ArmRegister.cs
Normal file
|
@ -0,0 +1,296 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn.Native
|
||||||
|
{
|
||||||
|
public enum ArmRegister
|
||||||
|
{
|
||||||
|
INVALID = 0,
|
||||||
|
|
||||||
|
X29,
|
||||||
|
X30,
|
||||||
|
NZCV,
|
||||||
|
SP,
|
||||||
|
WSP,
|
||||||
|
WZR,
|
||||||
|
XZR,
|
||||||
|
B0,
|
||||||
|
B1,
|
||||||
|
B2,
|
||||||
|
B3,
|
||||||
|
B4,
|
||||||
|
B5,
|
||||||
|
B6,
|
||||||
|
B7,
|
||||||
|
B8,
|
||||||
|
B9,
|
||||||
|
B10,
|
||||||
|
B11,
|
||||||
|
B12,
|
||||||
|
B13,
|
||||||
|
B14,
|
||||||
|
B15,
|
||||||
|
B16,
|
||||||
|
B17,
|
||||||
|
B18,
|
||||||
|
B19,
|
||||||
|
B20,
|
||||||
|
B21,
|
||||||
|
B22,
|
||||||
|
B23,
|
||||||
|
B24,
|
||||||
|
B25,
|
||||||
|
B26,
|
||||||
|
B27,
|
||||||
|
B28,
|
||||||
|
B29,
|
||||||
|
B30,
|
||||||
|
B31,
|
||||||
|
D0,
|
||||||
|
D1,
|
||||||
|
D2,
|
||||||
|
D3,
|
||||||
|
D4,
|
||||||
|
D5,
|
||||||
|
D6,
|
||||||
|
D7,
|
||||||
|
D8,
|
||||||
|
D9,
|
||||||
|
D10,
|
||||||
|
D11,
|
||||||
|
D12,
|
||||||
|
D13,
|
||||||
|
D14,
|
||||||
|
D15,
|
||||||
|
D16,
|
||||||
|
D17,
|
||||||
|
D18,
|
||||||
|
D19,
|
||||||
|
D20,
|
||||||
|
D21,
|
||||||
|
D22,
|
||||||
|
D23,
|
||||||
|
D24,
|
||||||
|
D25,
|
||||||
|
D26,
|
||||||
|
D27,
|
||||||
|
D28,
|
||||||
|
D29,
|
||||||
|
D30,
|
||||||
|
D31,
|
||||||
|
H0,
|
||||||
|
H1,
|
||||||
|
H2,
|
||||||
|
H3,
|
||||||
|
H4,
|
||||||
|
H5,
|
||||||
|
H6,
|
||||||
|
H7,
|
||||||
|
H8,
|
||||||
|
H9,
|
||||||
|
H10,
|
||||||
|
H11,
|
||||||
|
H12,
|
||||||
|
H13,
|
||||||
|
H14,
|
||||||
|
H15,
|
||||||
|
H16,
|
||||||
|
H17,
|
||||||
|
H18,
|
||||||
|
H19,
|
||||||
|
H20,
|
||||||
|
H21,
|
||||||
|
H22,
|
||||||
|
H23,
|
||||||
|
H24,
|
||||||
|
H25,
|
||||||
|
H26,
|
||||||
|
H27,
|
||||||
|
H28,
|
||||||
|
H29,
|
||||||
|
H30,
|
||||||
|
H31,
|
||||||
|
Q0,
|
||||||
|
Q1,
|
||||||
|
Q2,
|
||||||
|
Q3,
|
||||||
|
Q4,
|
||||||
|
Q5,
|
||||||
|
Q6,
|
||||||
|
Q7,
|
||||||
|
Q8,
|
||||||
|
Q9,
|
||||||
|
Q10,
|
||||||
|
Q11,
|
||||||
|
Q12,
|
||||||
|
Q13,
|
||||||
|
Q14,
|
||||||
|
Q15,
|
||||||
|
Q16,
|
||||||
|
Q17,
|
||||||
|
Q18,
|
||||||
|
Q19,
|
||||||
|
Q20,
|
||||||
|
Q21,
|
||||||
|
Q22,
|
||||||
|
Q23,
|
||||||
|
Q24,
|
||||||
|
Q25,
|
||||||
|
Q26,
|
||||||
|
Q27,
|
||||||
|
Q28,
|
||||||
|
Q29,
|
||||||
|
Q30,
|
||||||
|
Q31,
|
||||||
|
S0,
|
||||||
|
S1,
|
||||||
|
S2,
|
||||||
|
S3,
|
||||||
|
S4,
|
||||||
|
S5,
|
||||||
|
S6,
|
||||||
|
S7,
|
||||||
|
S8,
|
||||||
|
S9,
|
||||||
|
S10,
|
||||||
|
S11,
|
||||||
|
S12,
|
||||||
|
S13,
|
||||||
|
S14,
|
||||||
|
S15,
|
||||||
|
S16,
|
||||||
|
S17,
|
||||||
|
S18,
|
||||||
|
S19,
|
||||||
|
S20,
|
||||||
|
S21,
|
||||||
|
S22,
|
||||||
|
S23,
|
||||||
|
S24,
|
||||||
|
S25,
|
||||||
|
S26,
|
||||||
|
S27,
|
||||||
|
S28,
|
||||||
|
S29,
|
||||||
|
S30,
|
||||||
|
S31,
|
||||||
|
W0,
|
||||||
|
W1,
|
||||||
|
W2,
|
||||||
|
W3,
|
||||||
|
W4,
|
||||||
|
W5,
|
||||||
|
W6,
|
||||||
|
W7,
|
||||||
|
W8,
|
||||||
|
W9,
|
||||||
|
W10,
|
||||||
|
W11,
|
||||||
|
W12,
|
||||||
|
W13,
|
||||||
|
W14,
|
||||||
|
W15,
|
||||||
|
W16,
|
||||||
|
W17,
|
||||||
|
W18,
|
||||||
|
W19,
|
||||||
|
W20,
|
||||||
|
W21,
|
||||||
|
W22,
|
||||||
|
W23,
|
||||||
|
W24,
|
||||||
|
W25,
|
||||||
|
W26,
|
||||||
|
W27,
|
||||||
|
W28,
|
||||||
|
W29,
|
||||||
|
W30,
|
||||||
|
X0,
|
||||||
|
X1,
|
||||||
|
X2,
|
||||||
|
X3,
|
||||||
|
X4,
|
||||||
|
X5,
|
||||||
|
X6,
|
||||||
|
X7,
|
||||||
|
X8,
|
||||||
|
X9,
|
||||||
|
X10,
|
||||||
|
X11,
|
||||||
|
X12,
|
||||||
|
X13,
|
||||||
|
X14,
|
||||||
|
X15,
|
||||||
|
X16,
|
||||||
|
X17,
|
||||||
|
X18,
|
||||||
|
X19,
|
||||||
|
X20,
|
||||||
|
X21,
|
||||||
|
X22,
|
||||||
|
X23,
|
||||||
|
X24,
|
||||||
|
X25,
|
||||||
|
X26,
|
||||||
|
X27,
|
||||||
|
X28,
|
||||||
|
|
||||||
|
V0,
|
||||||
|
V1,
|
||||||
|
V2,
|
||||||
|
V3,
|
||||||
|
V4,
|
||||||
|
V5,
|
||||||
|
V6,
|
||||||
|
V7,
|
||||||
|
V8,
|
||||||
|
V9,
|
||||||
|
V10,
|
||||||
|
V11,
|
||||||
|
V12,
|
||||||
|
V13,
|
||||||
|
V14,
|
||||||
|
V15,
|
||||||
|
V16,
|
||||||
|
V17,
|
||||||
|
V18,
|
||||||
|
V19,
|
||||||
|
V20,
|
||||||
|
V21,
|
||||||
|
V22,
|
||||||
|
V23,
|
||||||
|
V24,
|
||||||
|
V25,
|
||||||
|
V26,
|
||||||
|
V27,
|
||||||
|
V28,
|
||||||
|
V29,
|
||||||
|
V30,
|
||||||
|
V31,
|
||||||
|
|
||||||
|
//> pseudo registers
|
||||||
|
PC, // program counter register
|
||||||
|
|
||||||
|
CPACR_EL1,
|
||||||
|
ESR,
|
||||||
|
|
||||||
|
//> thread registers
|
||||||
|
TPIDR_EL0,
|
||||||
|
TPIDRRO_EL0,
|
||||||
|
TPIDR_EL1,
|
||||||
|
|
||||||
|
PSTATE, // PSTATE pseudoregister
|
||||||
|
|
||||||
|
//> floating point control and status registers
|
||||||
|
FPCR,
|
||||||
|
FPSR,
|
||||||
|
|
||||||
|
ENDING, // <-- mark the end of the list of registers
|
||||||
|
|
||||||
|
//> alias registers
|
||||||
|
|
||||||
|
IP0 = X16,
|
||||||
|
IP1 = X17,
|
||||||
|
FP = X29,
|
||||||
|
LR = X30,
|
||||||
|
}
|
||||||
|
}
|
68
Ryujinx.Tests.Unicorn/Native/Interface.cs
Normal file
68
Ryujinx.Tests.Unicorn/Native/Interface.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Ryujinx.Tests.Unicorn;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn.Native
|
||||||
|
{
|
||||||
|
public class Interface
|
||||||
|
{
|
||||||
|
public static void Checked(UnicornError error)
|
||||||
|
{
|
||||||
|
if (error != UnicornError.UC_ERR_OK)
|
||||||
|
{
|
||||||
|
throw new UnicornException(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MarshalArrayOf<T>(IntPtr input, int length, out T[] output)
|
||||||
|
{
|
||||||
|
var size = Marshal.SizeOf(typeof(T));
|
||||||
|
output = new T[length];
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
IntPtr item = new IntPtr(input.ToInt64() + i * size);
|
||||||
|
output[i] = Marshal.PtrToStructure<T>(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern uint uc_version(out uint major, out uint minor);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_open(uint arch, uint mode, out IntPtr uc);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_close(IntPtr uc);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr uc_strerror(UnicornError err);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_reg_write(IntPtr uc, int regid, byte[] value);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_reg_read(IntPtr uc, int regid, byte[] value);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_mem_write(IntPtr uc, ulong address, byte[] bytes, ulong size);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_mem_read(IntPtr uc, ulong address, byte[] bytes, ulong size);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_emu_start(IntPtr uc, ulong begin, ulong until, ulong timeout, ulong count);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_mem_map(IntPtr uc, ulong address, ulong size, uint perms);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_mem_unmap(IntPtr uc, ulong address, ulong size);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_mem_protect(IntPtr uc, ulong address, ulong size, uint perms);
|
||||||
|
|
||||||
|
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern UnicornError uc_mem_regions(IntPtr uc, out IntPtr regions, out uint count);
|
||||||
|
}
|
||||||
|
}
|
16
Ryujinx.Tests.Unicorn/Native/UnicornArch.cs
Normal file
16
Ryujinx.Tests.Unicorn/Native/UnicornArch.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn.Native
|
||||||
|
{
|
||||||
|
public enum UnicornArch
|
||||||
|
{
|
||||||
|
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)
|
||||||
|
UC_ARCH_ARM64, // ARM-64, also called AArch64
|
||||||
|
UC_ARCH_MIPS, // Mips architecture
|
||||||
|
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
|
||||||
|
UC_ARCH_PPC, // PowerPC architecture (currently unsupported)
|
||||||
|
UC_ARCH_SPARC, // Sparc architecture
|
||||||
|
UC_ARCH_M68K, // M68K architecture
|
||||||
|
UC_ARCH_MAX,
|
||||||
|
}
|
||||||
|
}
|
13
Ryujinx.Tests.Unicorn/Native/UnicornMemoryRegion.cs
Normal file
13
Ryujinx.Tests.Unicorn/Native/UnicornMemoryRegion.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn.Native
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct UnicornMemoryRegion
|
||||||
|
{
|
||||||
|
public UInt64 begin; // begin address of the region (inclusive)
|
||||||
|
public UInt64 end; // end address of the region (inclusive)
|
||||||
|
public UInt32 perms; // memory permissions of the region
|
||||||
|
}
|
||||||
|
}
|
34
Ryujinx.Tests.Unicorn/Native/UnicornMode.cs
Normal file
34
Ryujinx.Tests.Unicorn/Native/UnicornMode.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn.Native
|
||||||
|
{
|
||||||
|
public enum UnicornMode
|
||||||
|
{
|
||||||
|
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
|
||||||
|
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
|
||||||
|
// arm / arm64
|
||||||
|
UC_MODE_ARM = 0, // ARM mode
|
||||||
|
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
|
||||||
|
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported)
|
||||||
|
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)
|
||||||
|
// mips
|
||||||
|
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
|
||||||
|
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
|
||||||
|
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
|
||||||
|
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
|
||||||
|
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
|
||||||
|
// x86 / x64
|
||||||
|
UC_MODE_16 = 1 << 1, // 16-bit mode
|
||||||
|
UC_MODE_32 = 1 << 2, // 32-bit mode
|
||||||
|
UC_MODE_64 = 1 << 3, // 64-bit mode
|
||||||
|
// ppc
|
||||||
|
UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported)
|
||||||
|
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
|
||||||
|
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)
|
||||||
|
// sparc
|
||||||
|
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
|
||||||
|
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
|
||||||
|
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)
|
||||||
|
// m68k
|
||||||
|
}
|
||||||
|
}
|
18
Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj
Normal file
18
Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||||
|
<PackageReference Include="System.Runtime.Intrinsics.Experimental" Version="4.5.0-rc1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
315
Ryujinx.Tests.Unicorn/UnicornAArch64.cs
Normal file
315
Ryujinx.Tests.Unicorn/UnicornAArch64.cs
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn
|
||||||
|
{
|
||||||
|
public class UnicornAArch64
|
||||||
|
{
|
||||||
|
internal readonly IntPtr uc;
|
||||||
|
|
||||||
|
public IndexedProperty<int, ulong> X
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new IndexedProperty<int, ulong>(
|
||||||
|
(int i) => GetX(i),
|
||||||
|
(int i, ulong value) => SetX(i, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexedProperty<int, Vector128<float>> Q
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new IndexedProperty<int, Vector128<float>>(
|
||||||
|
(int i) => GetQ(i),
|
||||||
|
(int i, Vector128<float> value) => SetQ(i, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong LR
|
||||||
|
{
|
||||||
|
get { return GetRegister(Native.ArmRegister.LR); }
|
||||||
|
set { SetRegister(Native.ArmRegister.LR, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong SP
|
||||||
|
{
|
||||||
|
get { return GetRegister(Native.ArmRegister.SP); }
|
||||||
|
set { SetRegister(Native.ArmRegister.SP, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong PC
|
||||||
|
{
|
||||||
|
get { return GetRegister(Native.ArmRegister.PC); }
|
||||||
|
set { SetRegister(Native.ArmRegister.PC, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Pstate
|
||||||
|
{
|
||||||
|
get { return (uint)GetRegister(Native.ArmRegister.PSTATE); }
|
||||||
|
set { SetRegister(Native.ArmRegister.PSTATE, (uint)value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Fpcr
|
||||||
|
{
|
||||||
|
get { return (int)GetRegister(Native.ArmRegister.FPCR); }
|
||||||
|
set { SetRegister(Native.ArmRegister.FPCR, (uint)value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Fpsr
|
||||||
|
{
|
||||||
|
get { return (int)GetRegister(Native.ArmRegister.FPSR); }
|
||||||
|
set { SetRegister(Native.ArmRegister.FPSR, (uint)value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OverflowFlag
|
||||||
|
{
|
||||||
|
get { return (Pstate & 0x10000000u) != 0; }
|
||||||
|
set { Pstate = (Pstate & ~0x10000000u) | (value ? 0x10000000u : 0u); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CarryFlag
|
||||||
|
{
|
||||||
|
get { return (Pstate & 0x20000000u) != 0; }
|
||||||
|
set { Pstate = (Pstate & ~0x20000000u) | (value ? 0x20000000u : 0u); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ZeroFlag
|
||||||
|
{
|
||||||
|
get { return (Pstate & 0x40000000u) != 0; }
|
||||||
|
set { Pstate = (Pstate & ~0x40000000u) | (value ? 0x40000000u : 0u); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NegativeFlag
|
||||||
|
{
|
||||||
|
get { return (Pstate & 0x80000000u) != 0; }
|
||||||
|
set { Pstate = (Pstate & ~0x80000000u) | (value ? 0x80000000u : 0u); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnicornAArch64()
|
||||||
|
{
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_open((uint)Native.UnicornArch.UC_ARCH_ARM64, (uint)Native.UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc));
|
||||||
|
SetRegister(Native.ArmRegister.CPACR_EL1, 0x00300000);
|
||||||
|
}
|
||||||
|
|
||||||
|
~UnicornAArch64()
|
||||||
|
{
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_close(uc));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunForCount(ulong count)
|
||||||
|
{
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_emu_start(uc, this.PC, 0xFFFFFFFFFFFFFFFFu, 0, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Step()
|
||||||
|
{
|
||||||
|
RunForCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Native.ArmRegister[] X_registers = new Native.ArmRegister[31]
|
||||||
|
{
|
||||||
|
Native.ArmRegister.X0,
|
||||||
|
Native.ArmRegister.X1,
|
||||||
|
Native.ArmRegister.X2,
|
||||||
|
Native.ArmRegister.X3,
|
||||||
|
Native.ArmRegister.X4,
|
||||||
|
Native.ArmRegister.X5,
|
||||||
|
Native.ArmRegister.X6,
|
||||||
|
Native.ArmRegister.X7,
|
||||||
|
Native.ArmRegister.X8,
|
||||||
|
Native.ArmRegister.X9,
|
||||||
|
Native.ArmRegister.X10,
|
||||||
|
Native.ArmRegister.X11,
|
||||||
|
Native.ArmRegister.X12,
|
||||||
|
Native.ArmRegister.X13,
|
||||||
|
Native.ArmRegister.X14,
|
||||||
|
Native.ArmRegister.X15,
|
||||||
|
Native.ArmRegister.X16,
|
||||||
|
Native.ArmRegister.X17,
|
||||||
|
Native.ArmRegister.X18,
|
||||||
|
Native.ArmRegister.X19,
|
||||||
|
Native.ArmRegister.X20,
|
||||||
|
Native.ArmRegister.X21,
|
||||||
|
Native.ArmRegister.X22,
|
||||||
|
Native.ArmRegister.X23,
|
||||||
|
Native.ArmRegister.X24,
|
||||||
|
Native.ArmRegister.X25,
|
||||||
|
Native.ArmRegister.X26,
|
||||||
|
Native.ArmRegister.X27,
|
||||||
|
Native.ArmRegister.X28,
|
||||||
|
Native.ArmRegister.X29,
|
||||||
|
Native.ArmRegister.X30,
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static Native.ArmRegister[] Q_registers = new Native.ArmRegister[32]
|
||||||
|
{
|
||||||
|
Native.ArmRegister.Q0,
|
||||||
|
Native.ArmRegister.Q1,
|
||||||
|
Native.ArmRegister.Q2,
|
||||||
|
Native.ArmRegister.Q3,
|
||||||
|
Native.ArmRegister.Q4,
|
||||||
|
Native.ArmRegister.Q5,
|
||||||
|
Native.ArmRegister.Q6,
|
||||||
|
Native.ArmRegister.Q7,
|
||||||
|
Native.ArmRegister.Q8,
|
||||||
|
Native.ArmRegister.Q9,
|
||||||
|
Native.ArmRegister.Q10,
|
||||||
|
Native.ArmRegister.Q11,
|
||||||
|
Native.ArmRegister.Q12,
|
||||||
|
Native.ArmRegister.Q13,
|
||||||
|
Native.ArmRegister.Q14,
|
||||||
|
Native.ArmRegister.Q15,
|
||||||
|
Native.ArmRegister.Q16,
|
||||||
|
Native.ArmRegister.Q17,
|
||||||
|
Native.ArmRegister.Q18,
|
||||||
|
Native.ArmRegister.Q19,
|
||||||
|
Native.ArmRegister.Q20,
|
||||||
|
Native.ArmRegister.Q21,
|
||||||
|
Native.ArmRegister.Q22,
|
||||||
|
Native.ArmRegister.Q23,
|
||||||
|
Native.ArmRegister.Q24,
|
||||||
|
Native.ArmRegister.Q25,
|
||||||
|
Native.ArmRegister.Q26,
|
||||||
|
Native.ArmRegister.Q27,
|
||||||
|
Native.ArmRegister.Q28,
|
||||||
|
Native.ArmRegister.Q29,
|
||||||
|
Native.ArmRegister.Q30,
|
||||||
|
Native.ArmRegister.Q31,
|
||||||
|
};
|
||||||
|
|
||||||
|
internal ulong GetRegister(Native.ArmRegister register)
|
||||||
|
{
|
||||||
|
byte[] value_bytes = new byte[8];
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_reg_read(uc, (int)register, value_bytes));
|
||||||
|
return (ulong)BitConverter.ToInt64(value_bytes, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void SetRegister(Native.ArmRegister register, ulong value)
|
||||||
|
{
|
||||||
|
byte[] value_bytes = BitConverter.GetBytes(value);
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_reg_write(uc, (int)register, value_bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Vector128<float> GetVector(Native.ArmRegister register)
|
||||||
|
{
|
||||||
|
byte[] value_bytes = new byte[16];
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_reg_read(uc, (int)register, value_bytes));
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* p = &value_bytes[0])
|
||||||
|
{
|
||||||
|
return Sse.LoadVector128((float*)p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void SetVector(Native.ArmRegister register, Vector128<float> value)
|
||||||
|
{
|
||||||
|
byte[] value_bytes = new byte[16];
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* p = &value_bytes[0])
|
||||||
|
{
|
||||||
|
Sse.Store((float*)p, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_reg_write(uc, (int)register, value_bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong GetX(int index)
|
||||||
|
{
|
||||||
|
Contract.Requires(index <= 30, "invalid register");
|
||||||
|
|
||||||
|
return GetRegister(X_registers[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetX(int index, ulong value)
|
||||||
|
{
|
||||||
|
Contract.Requires(index <= 30, "invalid register");
|
||||||
|
|
||||||
|
SetRegister(X_registers[index], value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector128<float> GetQ(int index)
|
||||||
|
{
|
||||||
|
Contract.Requires(index <= 31, "invalid vector");
|
||||||
|
|
||||||
|
return GetVector(Q_registers[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetQ(int index, Vector128<float> value)
|
||||||
|
{
|
||||||
|
Contract.Requires(index <= 31, "invalid vector");
|
||||||
|
|
||||||
|
SetVector(Q_registers[index], value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] MemoryRead(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
byte[] value = new byte[size];
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_mem_read(uc, address, value, size));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte MemoryRead8 (ulong address) { return MemoryRead(address, 1)[0]; }
|
||||||
|
public UInt16 MemoryRead16(ulong address) { return (UInt16)BitConverter.ToInt16(MemoryRead(address, 2), 0); }
|
||||||
|
public UInt32 MemoryRead32(ulong address) { return (UInt32)BitConverter.ToInt32(MemoryRead(address, 4), 0); }
|
||||||
|
public UInt64 MemoryRead64(ulong address) { return (UInt64)BitConverter.ToInt64(MemoryRead(address, 8), 0); }
|
||||||
|
|
||||||
|
public void MemoryWrite(ulong address, byte[] value)
|
||||||
|
{
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_mem_write(uc, address, value, (ulong)value.Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MemoryWrite8 (ulong address, byte value) { MemoryWrite(address, new byte[]{value}); }
|
||||||
|
public void MemoryWrite16(ulong address, Int16 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
|
||||||
|
public void MemoryWrite16(ulong address, UInt16 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
|
||||||
|
public void MemoryWrite32(ulong address, Int32 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
|
||||||
|
public void MemoryWrite32(ulong address, UInt32 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
|
||||||
|
public void MemoryWrite64(ulong address, Int64 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
|
||||||
|
public void MemoryWrite64(ulong address, UInt64 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
|
||||||
|
|
||||||
|
public void MemoryMap(ulong address, ulong size, MemoryPermission permissions)
|
||||||
|
{
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_mem_map(uc, address, size, (uint)permissions));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MemoryUnmap(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_mem_unmap(uc, address, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MemoryProtect(ulong address, ulong size, MemoryPermission permissions)
|
||||||
|
{
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_mem_protect(uc, address, size, (uint)permissions));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DumpMemoryInformation()
|
||||||
|
{
|
||||||
|
Native.Interface.Checked(Native.Interface.uc_mem_regions(uc, out IntPtr regions_raw, out uint length));
|
||||||
|
Native.Interface.MarshalArrayOf<Native.UnicornMemoryRegion>(regions_raw, (int)length, out var regions);
|
||||||
|
foreach (var region in regions)
|
||||||
|
{
|
||||||
|
Console.WriteLine("region: begin {0:X16} end {1:X16} perms {2:X8}", region.begin, region.end, region.perms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsAvailable()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Native.Interface.uc_version(out uint major, out uint minor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (DllNotFoundException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
Ryujinx.Tests.Unicorn/UnicornError.cs
Normal file
30
Ryujinx.Tests.Unicorn/UnicornError.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn
|
||||||
|
{
|
||||||
|
public enum UnicornError
|
||||||
|
{
|
||||||
|
UC_ERR_OK = 0, // No error: everything was fine
|
||||||
|
UC_ERR_NOMEM, // Out-Of-Memory error: uc_open(), uc_emulate()
|
||||||
|
UC_ERR_ARCH, // Unsupported architecture: uc_open()
|
||||||
|
UC_ERR_HANDLE, // Invalid handle
|
||||||
|
UC_ERR_MODE, // Invalid/unsupported mode: uc_open()
|
||||||
|
UC_ERR_VERSION, // Unsupported version (bindings)
|
||||||
|
UC_ERR_READ_UNMAPPED, // Quit emulation due to READ on unmapped memory: uc_emu_start()
|
||||||
|
UC_ERR_WRITE_UNMAPPED, // Quit emulation due to WRITE on unmapped memory: uc_emu_start()
|
||||||
|
UC_ERR_FETCH_UNMAPPED, // Quit emulation due to FETCH on unmapped memory: uc_emu_start()
|
||||||
|
UC_ERR_HOOK, // Invalid hook type: uc_hook_add()
|
||||||
|
UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start()
|
||||||
|
UC_ERR_MAP, // Invalid memory mapping: uc_mem_map()
|
||||||
|
UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start()
|
||||||
|
UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start()
|
||||||
|
UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation: uc_emu_start()
|
||||||
|
UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific function API)
|
||||||
|
UC_ERR_READ_UNALIGNED, // Unaligned read
|
||||||
|
UC_ERR_WRITE_UNALIGNED, // Unaligned write
|
||||||
|
UC_ERR_FETCH_UNALIGNED, // Unaligned fetch
|
||||||
|
UC_ERR_HOOK_EXIST, // hook for this event already existed
|
||||||
|
UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start()
|
||||||
|
UC_ERR_EXCEPTION // Unhandled CPU exception
|
||||||
|
}
|
||||||
|
}
|
23
Ryujinx.Tests.Unicorn/UnicornException.cs
Normal file
23
Ryujinx.Tests.Unicorn/UnicornException.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Unicorn
|
||||||
|
{
|
||||||
|
public class UnicornException : Exception
|
||||||
|
{
|
||||||
|
public readonly UnicornError Error;
|
||||||
|
|
||||||
|
internal UnicornException(UnicornError error)
|
||||||
|
{
|
||||||
|
Error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Message
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Marshal.PtrToStringAnsi(Native.Interface.uc_strerror(Error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
Ryujinx.Tests.Unicorn/libs/README.md
Normal file
3
Ryujinx.Tests.Unicorn/libs/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
The pre-compiled dynamic libraries in this directory are licenced under the GPLv2.
|
||||||
|
|
||||||
|
The source code for windows/unicorn.dll is available at: https://github.com/MerryMage/UnicornDotNet/tree/299451c02d9c810d2feca51f5e9cb6d8b2f38960
|
BIN
Ryujinx.Tests.Unicorn/libs/windows/unicorn.dll
Normal file
BIN
Ryujinx.Tests.Unicorn/libs/windows/unicorn.dll
Normal file
Binary file not shown.
|
@ -4,6 +4,8 @@ using ChocolArm64.State;
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
using Ryujinx.Tests.Unicorn;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Intrinsics;
|
using System.Runtime.Intrinsics;
|
||||||
|
@ -25,10 +27,22 @@ namespace Ryujinx.Tests.Cpu
|
||||||
private AMemory Memory;
|
private AMemory Memory;
|
||||||
private AThread Thread;
|
private AThread Thread;
|
||||||
|
|
||||||
|
private static bool UnicornAvailable;
|
||||||
|
private UnicornAArch64 UnicornEmu;
|
||||||
|
|
||||||
|
static CpuTest()
|
||||||
|
{
|
||||||
|
UnicornAvailable = UnicornAArch64.IsAvailable();
|
||||||
|
if (!UnicornAvailable)
|
||||||
|
{
|
||||||
|
Console.WriteLine("WARNING: Could not find unicorn");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
Position = 0x0;
|
Position = 0x1000;
|
||||||
Size = 0x1000;
|
Size = 0x1000;
|
||||||
|
|
||||||
EntryPoint = Position;
|
EntryPoint = Position;
|
||||||
|
@ -38,6 +52,13 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Memory = new AMemory(RamPointer);
|
Memory = new AMemory(RamPointer);
|
||||||
Memory.Map(Position, 0, Size);
|
Memory.Map(Position, 0, Size);
|
||||||
Thread = new AThread(Translator, Memory, EntryPoint);
|
Thread = new AThread(Translator, Memory, EntryPoint);
|
||||||
|
|
||||||
|
if (UnicornAvailable)
|
||||||
|
{
|
||||||
|
UnicornEmu = new UnicornAArch64();
|
||||||
|
UnicornEmu.MemoryMap((ulong)Position, (ulong)Size, MemoryPermission.READ | MemoryPermission.EXEC);
|
||||||
|
UnicornEmu.PC = (ulong)EntryPoint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TearDown]
|
[TearDown]
|
||||||
|
@ -46,6 +67,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Marshal.FreeHGlobal(RamPointer);
|
Marshal.FreeHGlobal(RamPointer);
|
||||||
Memory = null;
|
Memory = null;
|
||||||
Thread = null;
|
Thread = null;
|
||||||
|
UnicornEmu = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Reset()
|
protected void Reset()
|
||||||
|
@ -57,6 +79,10 @@ namespace Ryujinx.Tests.Cpu
|
||||||
protected void Opcode(uint Opcode)
|
protected void Opcode(uint Opcode)
|
||||||
{
|
{
|
||||||
Thread.Memory.WriteUInt32(Position, Opcode);
|
Thread.Memory.WriteUInt32(Position, Opcode);
|
||||||
|
if (UnicornAvailable)
|
||||||
|
{
|
||||||
|
UnicornEmu.MemoryWrite32((ulong)Position, Opcode);
|
||||||
|
}
|
||||||
Position += 4;
|
Position += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +107,24 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Thread.ThreadState.Negative = Negative;
|
Thread.ThreadState.Negative = Negative;
|
||||||
Thread.ThreadState.Fpcr = Fpcr;
|
Thread.ThreadState.Fpcr = Fpcr;
|
||||||
Thread.ThreadState.Fpsr = Fpsr;
|
Thread.ThreadState.Fpsr = Fpsr;
|
||||||
|
|
||||||
|
if (UnicornAvailable)
|
||||||
|
{
|
||||||
|
UnicornEmu.X[0] = X0;
|
||||||
|
UnicornEmu.X[1] = X1;
|
||||||
|
UnicornEmu.X[2] = X2;
|
||||||
|
UnicornEmu.X[3] = X3;
|
||||||
|
UnicornEmu.SP = X31;
|
||||||
|
UnicornEmu.Q[0] = V0;
|
||||||
|
UnicornEmu.Q[1] = V1;
|
||||||
|
UnicornEmu.Q[2] = V2;
|
||||||
|
UnicornEmu.OverflowFlag = Overflow;
|
||||||
|
UnicornEmu.CarryFlag = Carry;
|
||||||
|
UnicornEmu.ZeroFlag = Zero;
|
||||||
|
UnicornEmu.NegativeFlag = Negative;
|
||||||
|
UnicornEmu.Fpcr = Fpcr;
|
||||||
|
UnicornEmu.Fpsr = Fpsr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ExecuteOpcodes()
|
protected void ExecuteOpcodes()
|
||||||
|
@ -93,6 +137,11 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Thread.Execute();
|
Thread.Execute();
|
||||||
Wait.WaitOne();
|
Wait.WaitOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UnicornAvailable)
|
||||||
|
{
|
||||||
|
UnicornEmu.RunForCount((ulong)(Position - EntryPoint - 8) / 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AThreadState GetThreadState()
|
protected AThreadState GetThreadState()
|
||||||
|
@ -117,24 +166,124 @@ namespace Ryujinx.Tests.Cpu
|
||||||
return GetThreadState();
|
return GetThreadState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void CompareAgainstUnicorn()
|
||||||
|
{
|
||||||
|
if (!UnicornAvailable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(Thread.ThreadState.X0, Is.EqualTo(UnicornEmu.X[0]));
|
||||||
|
Assert.That(Thread.ThreadState.X1, Is.EqualTo(UnicornEmu.X[1]));
|
||||||
|
Assert.That(Thread.ThreadState.X2, Is.EqualTo(UnicornEmu.X[2]));
|
||||||
|
Assert.That(Thread.ThreadState.X3, Is.EqualTo(UnicornEmu.X[3]));
|
||||||
|
Assert.That(Thread.ThreadState.X4, Is.EqualTo(UnicornEmu.X[4]));
|
||||||
|
Assert.That(Thread.ThreadState.X5, Is.EqualTo(UnicornEmu.X[5]));
|
||||||
|
Assert.That(Thread.ThreadState.X6, Is.EqualTo(UnicornEmu.X[6]));
|
||||||
|
Assert.That(Thread.ThreadState.X7, Is.EqualTo(UnicornEmu.X[7]));
|
||||||
|
Assert.That(Thread.ThreadState.X8, Is.EqualTo(UnicornEmu.X[8]));
|
||||||
|
Assert.That(Thread.ThreadState.X9, Is.EqualTo(UnicornEmu.X[9]));
|
||||||
|
Assert.That(Thread.ThreadState.X10, Is.EqualTo(UnicornEmu.X[10]));
|
||||||
|
Assert.That(Thread.ThreadState.X11, Is.EqualTo(UnicornEmu.X[11]));
|
||||||
|
Assert.That(Thread.ThreadState.X12, Is.EqualTo(UnicornEmu.X[12]));
|
||||||
|
Assert.That(Thread.ThreadState.X13, Is.EqualTo(UnicornEmu.X[13]));
|
||||||
|
Assert.That(Thread.ThreadState.X14, Is.EqualTo(UnicornEmu.X[14]));
|
||||||
|
Assert.That(Thread.ThreadState.X15, Is.EqualTo(UnicornEmu.X[15]));
|
||||||
|
Assert.That(Thread.ThreadState.X16, Is.EqualTo(UnicornEmu.X[16]));
|
||||||
|
Assert.That(Thread.ThreadState.X17, Is.EqualTo(UnicornEmu.X[17]));
|
||||||
|
Assert.That(Thread.ThreadState.X18, Is.EqualTo(UnicornEmu.X[18]));
|
||||||
|
Assert.That(Thread.ThreadState.X19, Is.EqualTo(UnicornEmu.X[19]));
|
||||||
|
Assert.That(Thread.ThreadState.X20, Is.EqualTo(UnicornEmu.X[20]));
|
||||||
|
Assert.That(Thread.ThreadState.X21, Is.EqualTo(UnicornEmu.X[21]));
|
||||||
|
Assert.That(Thread.ThreadState.X22, Is.EqualTo(UnicornEmu.X[22]));
|
||||||
|
Assert.That(Thread.ThreadState.X23, Is.EqualTo(UnicornEmu.X[23]));
|
||||||
|
Assert.That(Thread.ThreadState.X24, Is.EqualTo(UnicornEmu.X[24]));
|
||||||
|
Assert.That(Thread.ThreadState.X25, Is.EqualTo(UnicornEmu.X[25]));
|
||||||
|
Assert.That(Thread.ThreadState.X26, Is.EqualTo(UnicornEmu.X[26]));
|
||||||
|
Assert.That(Thread.ThreadState.X27, Is.EqualTo(UnicornEmu.X[27]));
|
||||||
|
Assert.That(Thread.ThreadState.X28, Is.EqualTo(UnicornEmu.X[28]));
|
||||||
|
Assert.That(Thread.ThreadState.X29, Is.EqualTo(UnicornEmu.X[29]));
|
||||||
|
Assert.That(Thread.ThreadState.X30, Is.EqualTo(UnicornEmu.X[30]));
|
||||||
|
Assert.That(Thread.ThreadState.X31, Is.EqualTo(UnicornEmu.SP));
|
||||||
|
Assert.That(Thread.ThreadState.V0, Is.EqualTo(UnicornEmu.Q[0]));
|
||||||
|
Assert.That(Thread.ThreadState.V1, Is.EqualTo(UnicornEmu.Q[1]));
|
||||||
|
Assert.That(Thread.ThreadState.V2, Is.EqualTo(UnicornEmu.Q[2]));
|
||||||
|
Assert.That(Thread.ThreadState.V3, Is.EqualTo(UnicornEmu.Q[3]));
|
||||||
|
Assert.That(Thread.ThreadState.V4, Is.EqualTo(UnicornEmu.Q[4]));
|
||||||
|
Assert.That(Thread.ThreadState.V5, Is.EqualTo(UnicornEmu.Q[5]));
|
||||||
|
Assert.That(Thread.ThreadState.V6, Is.EqualTo(UnicornEmu.Q[6]));
|
||||||
|
Assert.That(Thread.ThreadState.V7, Is.EqualTo(UnicornEmu.Q[7]));
|
||||||
|
Assert.That(Thread.ThreadState.V8, Is.EqualTo(UnicornEmu.Q[8]));
|
||||||
|
Assert.That(Thread.ThreadState.V9, Is.EqualTo(UnicornEmu.Q[9]));
|
||||||
|
Assert.That(Thread.ThreadState.V10, Is.EqualTo(UnicornEmu.Q[10]));
|
||||||
|
Assert.That(Thread.ThreadState.V11, Is.EqualTo(UnicornEmu.Q[11]));
|
||||||
|
Assert.That(Thread.ThreadState.V12, Is.EqualTo(UnicornEmu.Q[12]));
|
||||||
|
Assert.That(Thread.ThreadState.V13, Is.EqualTo(UnicornEmu.Q[13]));
|
||||||
|
Assert.That(Thread.ThreadState.V14, Is.EqualTo(UnicornEmu.Q[14]));
|
||||||
|
Assert.That(Thread.ThreadState.V15, Is.EqualTo(UnicornEmu.Q[15]));
|
||||||
|
Assert.That(Thread.ThreadState.V16, Is.EqualTo(UnicornEmu.Q[16]));
|
||||||
|
Assert.That(Thread.ThreadState.V17, Is.EqualTo(UnicornEmu.Q[17]));
|
||||||
|
Assert.That(Thread.ThreadState.V18, Is.EqualTo(UnicornEmu.Q[18]));
|
||||||
|
Assert.That(Thread.ThreadState.V19, Is.EqualTo(UnicornEmu.Q[19]));
|
||||||
|
Assert.That(Thread.ThreadState.V20, Is.EqualTo(UnicornEmu.Q[20]));
|
||||||
|
Assert.That(Thread.ThreadState.V21, Is.EqualTo(UnicornEmu.Q[21]));
|
||||||
|
Assert.That(Thread.ThreadState.V22, Is.EqualTo(UnicornEmu.Q[22]));
|
||||||
|
Assert.That(Thread.ThreadState.V23, Is.EqualTo(UnicornEmu.Q[23]));
|
||||||
|
Assert.That(Thread.ThreadState.V24, Is.EqualTo(UnicornEmu.Q[24]));
|
||||||
|
Assert.That(Thread.ThreadState.V25, Is.EqualTo(UnicornEmu.Q[25]));
|
||||||
|
Assert.That(Thread.ThreadState.V26, Is.EqualTo(UnicornEmu.Q[26]));
|
||||||
|
Assert.That(Thread.ThreadState.V27, Is.EqualTo(UnicornEmu.Q[27]));
|
||||||
|
Assert.That(Thread.ThreadState.V28, Is.EqualTo(UnicornEmu.Q[28]));
|
||||||
|
Assert.That(Thread.ThreadState.V29, Is.EqualTo(UnicornEmu.Q[29]));
|
||||||
|
Assert.That(Thread.ThreadState.V30, Is.EqualTo(UnicornEmu.Q[30]));
|
||||||
|
Assert.That(Thread.ThreadState.V31, Is.EqualTo(UnicornEmu.Q[31]));
|
||||||
|
Assert.That(Thread.ThreadState.V31, Is.EqualTo(UnicornEmu.Q[31]));
|
||||||
|
Assert.That(Thread.ThreadState.Fpcr, Is.EqualTo(UnicornEmu.Fpcr));
|
||||||
|
Assert.That(Thread.ThreadState.Fpsr & 0x08000000, Is.EqualTo(UnicornEmu.Fpsr & 0x08000000));
|
||||||
|
Assert.That(Thread.ThreadState.Overflow, Is.EqualTo(UnicornEmu.OverflowFlag));
|
||||||
|
Assert.That(Thread.ThreadState.Carry, Is.EqualTo(UnicornEmu.CarryFlag));
|
||||||
|
Assert.That(Thread.ThreadState.Zero, Is.EqualTo(UnicornEmu.ZeroFlag));
|
||||||
|
Assert.That(Thread.ThreadState.Negative, Is.EqualTo(UnicornEmu.NegativeFlag));
|
||||||
|
}
|
||||||
|
|
||||||
protected static Vector128<float> MakeVectorE0(double E0)
|
protected static Vector128<float> MakeVectorE0(double E0)
|
||||||
{
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
return Sse.StaticCast<long, float>(Sse2.SetVector128(0, BitConverter.DoubleToInt64Bits(E0)));
|
return Sse.StaticCast<long, float>(Sse2.SetVector128(0, BitConverter.DoubleToInt64Bits(E0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Vector128<float> MakeVectorE0E1(double E0, double E1)
|
protected static Vector128<float> MakeVectorE0E1(double E0, double E1)
|
||||||
{
|
{
|
||||||
return Sse.StaticCast<long, float>(Sse2.SetVector128(BitConverter.DoubleToInt64Bits(E1),
|
if (!Sse2.IsSupported)
|
||||||
BitConverter.DoubleToInt64Bits(E0)));
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sse.StaticCast<long, float>(
|
||||||
|
Sse2.SetVector128(BitConverter.DoubleToInt64Bits(E1), BitConverter.DoubleToInt64Bits(E0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Vector128<float> MakeVectorE1(double E1)
|
protected static Vector128<float> MakeVectorE1(double E1)
|
||||||
{
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
return Sse.StaticCast<long, float>(Sse2.SetVector128(BitConverter.DoubleToInt64Bits(E1), 0));
|
return Sse.StaticCast<long, float>(Sse2.SetVector128(BitConverter.DoubleToInt64Bits(E1), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static double VectorExtractDouble(Vector128<float> Vector, byte Index)
|
protected static double VectorExtractDouble(Vector128<float> Vector, byte Index)
|
||||||
{
|
{
|
||||||
|
if (!Sse41.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
long Value = Sse41.Extract(Sse.StaticCast<float, long>(Vector), Index);
|
long Value = Sse41.Extract(Sse.StaticCast<float, long>(Vector), Index);
|
||||||
|
|
||||||
return BitConverter.Int64BitsToDouble(Value);
|
return BitConverter.Int64BitsToDouble(Value);
|
||||||
|
@ -142,26 +291,51 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
protected static Vector128<float> MakeVectorE0(ulong E0)
|
protected static Vector128<float> MakeVectorE0(ulong E0)
|
||||||
{
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
return Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, E0));
|
return Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, E0));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Vector128<float> MakeVectorE0E1(ulong E0, ulong E1)
|
protected static Vector128<float> MakeVectorE0E1(ulong E0, ulong E1)
|
||||||
{
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
return Sse.StaticCast<ulong, float>(Sse2.SetVector128(E1, E0));
|
return Sse.StaticCast<ulong, float>(Sse2.SetVector128(E1, E0));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Vector128<float> MakeVectorE1(ulong E1)
|
protected static Vector128<float> MakeVectorE1(ulong E1)
|
||||||
{
|
{
|
||||||
|
if (!Sse2.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
return Sse.StaticCast<ulong, float>(Sse2.SetVector128(E1, 0));
|
return Sse.StaticCast<ulong, float>(Sse2.SetVector128(E1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static ulong GetVectorE0(Vector128<float> Vector)
|
protected static ulong GetVectorE0(Vector128<float> Vector)
|
||||||
{
|
{
|
||||||
|
if (!Sse41.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
return Sse41.Extract(Sse.StaticCast<float, ulong>(Vector), (byte)0);
|
return Sse41.Extract(Sse.StaticCast<float, ulong>(Vector), (byte)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static ulong GetVectorE1(Vector128<float> Vector)
|
protected static ulong GetVectorE1(Vector128<float> Vector)
|
||||||
{
|
{
|
||||||
|
if (!Sse41.IsSupported)
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
return Sse41.Extract(Sse.StaticCast<float, ulong>(Vector), (byte)1);
|
return Sse41.Extract(Sse.StaticCast<float, ulong>(Vector), (byte)1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CLS <Wd>, <Wn>")]
|
[Test, Description("CLS <Wd>, <Wn>")]
|
||||||
|
@ -101,6 +102,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CLZ <Wd>, <Wn>")]
|
[Test, Description("CLZ <Wd>, <Wn>")]
|
||||||
|
@ -129,6 +131,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("RBIT <Xd>, <Xn>")]
|
[Test, Description("RBIT <Xd>, <Xn>")]
|
||||||
|
@ -157,6 +160,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("RBIT <Wd>, <Wn>")]
|
[Test, Description("RBIT <Wd>, <Wn>")]
|
||||||
|
@ -185,6 +189,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("REV16 <Xd>, <Xn>")]
|
[Test, Description("REV16 <Xd>, <Xn>")]
|
||||||
|
@ -213,6 +218,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("REV16 <Wd>, <Wn>")]
|
[Test, Description("REV16 <Wd>, <Wn>")]
|
||||||
|
@ -241,6 +247,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("REV32 <Xd>, <Xn>")]
|
[Test, Description("REV32 <Xd>, <Xn>")]
|
||||||
|
@ -269,6 +276,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("REV <Wd>, <Wn>")]
|
[Test, Description("REV <Wd>, <Wn>")]
|
||||||
|
@ -297,6 +305,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("REV64 <Xd>, <Xn>")]
|
[Test, Description("REV64 <Xd>, <Xn>")]
|
||||||
|
@ -325,6 +334,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADD <Wd|WSP>, <Wn|WSP>, #<imm>{, <shift>}")]
|
[Test, Description("ADD <Wd|WSP>, <Wn|WSP>, #<imm>{, <shift>}")]
|
||||||
|
@ -105,6 +106,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Xd>, <Xn|SP>, #<imm>{, <shift>}")]
|
[Test, Description("ADDS <Xd>, <Xn|SP>, #<imm>{, <shift>}")]
|
||||||
|
@ -156,6 +158,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Wd>, <Wn|WSP>, #<imm>{, <shift>}")]
|
[Test, Description("ADDS <Wd>, <Wn|WSP>, #<imm>{, <shift>}")]
|
||||||
|
@ -207,6 +210,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("AND <Xd|SP>, <Xn>, #<imm>")]
|
[Test, Description("AND <Xd|SP>, <Xn>, #<imm>")]
|
||||||
|
@ -240,6 +244,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("AND <Xd|SP>, <Xn>, #<imm>")]
|
[Test, Description("AND <Xd|SP>, <Xn>, #<imm>")]
|
||||||
|
@ -273,6 +278,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("AND <Wd|WSP>, <Wn>, #<imm>")]
|
[Test, Description("AND <Wd|WSP>, <Wn>, #<imm>")]
|
||||||
|
@ -306,6 +312,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ANDS <Xd>, <Xn>, #<imm>")]
|
[Test, Description("ANDS <Xd>, <Xn>, #<imm>")]
|
||||||
|
@ -343,6 +350,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ANDS <Xd>, <Xn>, #<imm>")]
|
[Test, Description("ANDS <Xd>, <Xn>, #<imm>")]
|
||||||
|
@ -380,6 +388,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ANDS <Wd>, <Wn>, #<imm>")]
|
[Test, Description("ANDS <Wd>, <Wn>, #<imm>")]
|
||||||
|
@ -417,6 +426,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("EOR <Xd|SP>, <Xn>, #<imm>")]
|
[Test, Description("EOR <Xd|SP>, <Xn>, #<imm>")]
|
||||||
|
@ -450,6 +460,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("EOR <Xd|SP>, <Xn>, #<imm>")]
|
[Test, Description("EOR <Xd|SP>, <Xn>, #<imm>")]
|
||||||
|
@ -483,6 +494,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("EOR <Wd>, <Wn>, #<imm>")]
|
[Test, Description("EOR <Wd>, <Wn>, #<imm>")]
|
||||||
|
@ -516,6 +528,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ORR <Xd|SP>, <Xn>, #<imm>")]
|
[Test, Description("ORR <Xd|SP>, <Xn>, #<imm>")]
|
||||||
|
@ -549,6 +562,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ORR <Xd|SP>, <Xn>, #<imm>")]
|
[Test, Description("ORR <Xd|SP>, <Xn>, #<imm>")]
|
||||||
|
@ -582,6 +596,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ORR <Wd|WSP>, <Wn>, #<imm>")]
|
[Test, Description("ORR <Wd|WSP>, <Wn>, #<imm>")]
|
||||||
|
@ -615,6 +630,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}")]
|
[Test, Description("SUB <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}")]
|
||||||
|
@ -659,6 +675,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Wd|WSP>, <Wn|WSP>, #<imm>{, <shift>}")]
|
[Test, Description("SUB <Wd|WSP>, <Wn|WSP>, #<imm>{, <shift>}")]
|
||||||
|
@ -703,6 +720,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Xd>, <Xn|SP>, #<imm>{, <shift>}")]
|
[Test, Description("SUBS <Xd>, <Xn|SP>, #<imm>{, <shift>}")]
|
||||||
|
@ -754,6 +772,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Wd>, <Wn|WSP>, #<imm>{, <shift>}")]
|
[Test, Description("SUBS <Wd>, <Wn|WSP>, #<imm>{, <shift>}")]
|
||||||
|
@ -805,6 +824,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADC <Wd>, <Wn>, <Wm>")]
|
[Test, Description("ADC <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -85,6 +86,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADCS <Xd>, <Xn>, <Xm>")]
|
[Test, Description("ADCS <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -125,6 +127,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADCS <Wd>, <Wn>, <Wm>")]
|
[Test, Description("ADCS <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -165,6 +168,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADD <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("ADD <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -200,6 +204,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADD <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("ADD <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -234,6 +239,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,6 +282,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("ADDS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -317,6 +324,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("AND <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("AND <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -352,6 +360,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("AND <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("AND <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -387,6 +396,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ANDS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("ANDS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -428,6 +438,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ANDS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("ANDS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -469,6 +480,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ASRV <Xd>, <Xn>, <Xm>")]
|
[Test, Description("ASRV <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -501,6 +513,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ASRV <Wd>, <Wn>, <Wm>")]
|
[Test, Description("ASRV <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -533,6 +546,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("BIC <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("BIC <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -568,6 +582,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("BIC <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("BIC <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -603,6 +618,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("BICS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("BICS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -644,6 +660,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("BICS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("BICS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -685,6 +702,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CRC32X <Wd>, <Wn>, <Xm>")]
|
[Test, Description("CRC32X <Wd>, <Wn>, <Xm>")]
|
||||||
|
@ -718,6 +736,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CRC32W <Wd>, <Wn>, <Wm>")]
|
[Test, Description("CRC32W <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -749,6 +768,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CRC32H <Wd>, <Wn>, <Wm>")]
|
[Test, Description("CRC32H <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -780,6 +800,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CRC32B <Wd>, <Wn>, <Wm>")]
|
[Test, Description("CRC32B <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -811,6 +832,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CRC32CX <Wd>, <Wn>, <Xm>")]
|
[Test, Description("CRC32CX <Wd>, <Wn>, <Xm>")]
|
||||||
|
@ -844,6 +866,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CRC32CW <Wd>, <Wn>, <Wm>")]
|
[Test, Description("CRC32CW <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -875,6 +898,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CRC32CH <Wd>, <Wn>, <Wm>")]
|
[Test, Description("CRC32CH <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -906,6 +930,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CRC32CB <Wd>, <Wn>, <Wm>")]
|
[Test, Description("CRC32CB <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -937,6 +962,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("EON <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("EON <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -972,6 +998,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("EON <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("EON <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -1007,6 +1034,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("EOR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("EOR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -1042,6 +1070,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("EOR <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("EOR <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -1077,6 +1106,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("EXTR <Xd>, <Xn>, <Xm>, #<lsb>")]
|
[Test, Description("EXTR <Xd>, <Xn>, <Xm>, #<lsb>")]
|
||||||
|
@ -1111,6 +1141,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("EXTR <Wd>, <Wn>, <Wm>, #<lsb>")]
|
[Test, Description("EXTR <Wd>, <Wn>, <Wm>, #<lsb>")]
|
||||||
|
@ -1145,6 +1176,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("LSLV <Xd>, <Xn>, <Xm>")]
|
[Test, Description("LSLV <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -1177,6 +1209,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("LSLV <Wd>, <Wn>, <Wm>")]
|
[Test, Description("LSLV <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -1209,6 +1242,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("LSRV <Xd>, <Xn>, <Xm>")]
|
[Test, Description("LSRV <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -1241,6 +1275,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("LSRV <Wd>, <Wn>, <Wm>")]
|
[Test, Description("LSRV <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -1273,6 +1308,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ORN <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("ORN <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -1308,6 +1344,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ORN <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("ORN <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -1343,6 +1380,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ORR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("ORR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -1378,6 +1416,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ORR <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("ORR <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -1413,6 +1452,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("RORV <Xd>, <Xn>, <Xm>")]
|
[Test, Description("RORV <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -1445,6 +1485,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("RORV <Wd>, <Wn>, <Wm>")]
|
[Test, Description("RORV <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -1477,6 +1518,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SBC <Xd>, <Xn>, <Xm>")]
|
[Test, Description("SBC <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -1511,6 +1553,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SBC <Wd>, <Wn>, <Wm>")]
|
[Test, Description("SBC <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -1545,6 +1588,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SBCS <Xd>, <Xn>, <Xm>")]
|
[Test, Description("SBCS <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -1585,6 +1629,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SBCS <Wd>, <Wn>, <Wm>")]
|
[Test, Description("SBCS <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -1625,6 +1670,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SDIV <Xd>, <Xn>, <Xm>")]
|
[Test, Description("SDIV <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -1657,6 +1703,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SDIV <Wd>, <Wn>, <Wm>")]
|
[Test, Description("SDIV <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -1689,6 +1736,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("SUB <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -1724,6 +1772,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("SUB <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -1759,6 +1808,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
[Test, Description("SUBS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||||
|
@ -1800,6 +1850,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
[Test, Description("SUBS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||||
|
@ -1841,6 +1892,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("UDIV <Xd>, <Xn>, <Xm>")]
|
[Test, Description("UDIV <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -1873,6 +1925,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("UDIV <Wd>, <Wn>, <Wm>")]
|
[Test, Description("UDIV <Wd>, <Wn>, <Wm>")]
|
||||||
|
@ -1905,6 +1958,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADD <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("ADD <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -116,6 +117,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADD <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("ADD <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -166,6 +168,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADD <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("ADD <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -216,6 +219,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADD <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("ADD <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -266,6 +270,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADD <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("ADD <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -316,6 +321,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADD <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("ADD <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -366,6 +372,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Xd>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
[Test, Description("ADDS <Xd>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -410,6 +417,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("ADDS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -455,6 +463,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("ADDS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -500,6 +509,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("ADDS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -545,6 +555,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("ADDS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -590,6 +601,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("ADDS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -635,6 +647,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("ADDS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("ADDS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -680,6 +693,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Xd|SP>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
[Test, Description("SUB <Xd|SP>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -729,6 +743,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("SUB <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -779,6 +794,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("SUB <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -829,6 +845,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("SUB <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -879,6 +896,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(SP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("SUB <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -929,6 +947,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("SUB <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -979,6 +998,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUB <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("SUB <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -1029,6 +1049,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(WSP));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Xd>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
[Test, Description("SUBS <Xd>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -1073,6 +1094,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("SUBS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -1118,6 +1140,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("SUBS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -1163,6 +1186,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
[Test, Description("SUBS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||||
|
@ -1208,6 +1232,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("SUBS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -1253,6 +1278,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("SUBS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -1298,6 +1324,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SUBS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
[Test, Description("SUBS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||||
|
@ -1343,6 +1370,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("BFM <Wd>, <Wn>, #<immr>, #<imms>")]
|
[Test, Description("BFM <Wd>, <Wn>, #<immr>, #<imms>")]
|
||||||
|
@ -83,6 +84,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SBFM <Xd>, <Xn>, #<immr>, #<imms>")]
|
[Test, Description("SBFM <Xd>, <Xn>, #<immr>, #<imms>")]
|
||||||
|
@ -114,6 +116,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SBFM <Wd>, <Wn>, #<immr>, #<imms>")]
|
[Test, Description("SBFM <Wd>, <Wn>, #<immr>, #<imms>")]
|
||||||
|
@ -145,6 +148,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("UBFM <Xd>, <Xn>, #<immr>, #<imms>")]
|
[Test, Description("UBFM <Xd>, <Xn>, #<immr>, #<imms>")]
|
||||||
|
@ -176,6 +180,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("UBFM <Wd>, <Wn>, #<immr>, #<imms>")]
|
[Test, Description("UBFM <Wd>, <Wn>, #<immr>, #<imms>")]
|
||||||
|
@ -207,6 +212,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CCMN <Wn>, #<imm>, #<nzcv>, <cond>")]
|
[Test, Description("CCMN <Wn>, #<imm>, #<nzcv>, <cond>")]
|
||||||
|
@ -81,6 +82,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CCMP <Xn>, #<imm>, #<nzcv>, <cond>")]
|
[Test, Description("CCMP <Xn>, #<imm>, #<nzcv>, <cond>")]
|
||||||
|
@ -113,6 +115,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CCMP <Wn>, #<imm>, #<nzcv>, <cond>")]
|
[Test, Description("CCMP <Wn>, #<imm>, #<nzcv>, <cond>")]
|
||||||
|
@ -145,6 +148,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CCMN <Wn>, <Wm>, #<nzcv>, <cond>")]
|
[Test, Description("CCMN <Wn>, <Wm>, #<nzcv>, <cond>")]
|
||||||
|
@ -87,6 +88,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CCMP <Xn>, <Xm>, #<nzcv>, <cond>")]
|
[Test, Description("CCMP <Xn>, <Xm>, #<nzcv>, <cond>")]
|
||||||
|
@ -122,6 +124,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CCMP <Wn>, <Wm>, #<nzcv>, <cond>")]
|
[Test, Description("CCMP <Wn>, <Wm>, #<nzcv>, <cond>")]
|
||||||
|
@ -157,6 +160,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
Assert.That(ThreadState.Carry, Is.EqualTo(Shared.PSTATE.C));
|
||||||
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
Assert.That(ThreadState.Overflow, Is.EqualTo(Shared.PSTATE.V));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CSEL <Wd>, <Wn>, <Wm>, <cond>")]
|
[Test, Description("CSEL <Wd>, <Wn>, <Wm>, <cond>")]
|
||||||
|
@ -91,6 +92,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CSINC <Xd>, <Xn>, <Xm>, <cond>")]
|
[Test, Description("CSINC <Xd>, <Xn>, <Xm>, <cond>")]
|
||||||
|
@ -128,6 +130,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CSINC <Wd>, <Wn>, <Wm>, <cond>")]
|
[Test, Description("CSINC <Wd>, <Wn>, <Wm>, <cond>")]
|
||||||
|
@ -165,6 +168,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CSINV <Xd>, <Xn>, <Xm>, <cond>")]
|
[Test, Description("CSINV <Xd>, <Xn>, <Xm>, <cond>")]
|
||||||
|
@ -202,6 +206,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CSINV <Wd>, <Wn>, <Wm>, <cond>")]
|
[Test, Description("CSINV <Wd>, <Wn>, <Wm>, <cond>")]
|
||||||
|
@ -239,6 +244,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CSNEG <Xd>, <Xn>, <Xm>, <cond>")]
|
[Test, Description("CSNEG <Xd>, <Xn>, <Xm>, <cond>")]
|
||||||
|
@ -276,6 +282,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("CSNEG <Wd>, <Wn>, <Wm>, <cond>")]
|
[Test, Description("CSNEG <Wd>, <Wn>, <Wm>, <cond>")]
|
||||||
|
@ -313,6 +320,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("MOVK <Wd>, #<imm>{, LSL #<shift>}")]
|
[Test, Description("MOVK <Wd>, #<imm>{, LSL #<shift>}")]
|
||||||
|
@ -75,6 +76,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("MOVN <Xd>, #<imm>{, LSL #<shift>}")]
|
[Test, Description("MOVN <Xd>, #<imm>{, LSL #<shift>}")]
|
||||||
|
@ -102,6 +104,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("MOVN <Wd>, #<imm>{, LSL #<shift>}")]
|
[Test, Description("MOVN <Wd>, #<imm>{, LSL #<shift>}")]
|
||||||
|
@ -129,6 +132,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("MOVZ <Xd>, #<imm>{, LSL #<shift>}")]
|
[Test, Description("MOVZ <Xd>, #<imm>{, LSL #<shift>}")]
|
||||||
|
@ -156,6 +160,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("MOVZ <Wd>, #<imm>{, LSL #<shift>}")]
|
[Test, Description("MOVZ <Wd>, #<imm>{, LSL #<shift>}")]
|
||||||
|
@ -183,6 +188,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("MADD <Wd>, <Wn>, <Wm>, <Wa>")]
|
[Test, Description("MADD <Wd>, <Wn>, <Wm>, <Wa>")]
|
||||||
|
@ -89,6 +90,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("MSUB <Xd>, <Xn>, <Xm>, <Xa>")]
|
[Test, Description("MSUB <Xd>, <Xn>, <Xm>, <Xa>")]
|
||||||
|
@ -125,6 +127,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("MSUB <Wd>, <Wn>, <Wm>, <Wa>")]
|
[Test, Description("MSUB <Wd>, <Wn>, <Wm>, <Wa>")]
|
||||||
|
@ -161,6 +164,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
Assert.That((uint)ThreadState.X31, Is.EqualTo(_W31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SMADDL <Xd>, <Wn>, <Wm>, <Xa>")]
|
[Test, Description("SMADDL <Xd>, <Wn>, <Wm>, <Xa>")]
|
||||||
|
@ -197,6 +201,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("UMADDL <Xd>, <Wn>, <Wm>, <Xa>")]
|
[Test, Description("UMADDL <Xd>, <Wn>, <Wm>, <Xa>")]
|
||||||
|
@ -233,6 +238,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SMSUBL <Xd>, <Wn>, <Wm>, <Xa>")]
|
[Test, Description("SMSUBL <Xd>, <Wn>, <Wm>, <Xa>")]
|
||||||
|
@ -269,6 +275,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("UMSUBL <Xd>, <Wn>, <Wm>, <Xa>")]
|
[Test, Description("UMSUBL <Xd>, <Wn>, <Wm>, <Xa>")]
|
||||||
|
@ -305,6 +312,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("SMULH <Xd>, <Xn>, <Xm>")]
|
[Test, Description("SMULH <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -337,6 +345,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("UMULH <Xd>, <Xn>, <Xm>")]
|
[Test, Description("UMULH <Xd>, <Xn>, <Xm>")]
|
||||||
|
@ -369,6 +378,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
Assert.That((ulong)ThreadState.X31, Is.EqualTo(_X31));
|
||||||
}
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -33,6 +33,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
V1: Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, A)),
|
V1: Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, A)),
|
||||||
V2: Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, B)));
|
V2: Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, B)));
|
||||||
Assert.AreEqual(Result, Sse41.Extract(Sse.StaticCast<float, ulong>(ThreadState.V0), 0));
|
Assert.AreEqual(Result, Sse41.Extract(Sse.StaticCast<float, ulong>(ThreadState.V0), 0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x80000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u)]
|
[TestCase(0x80000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u)]
|
||||||
|
@ -59,6 +60,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
||||||
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x1E225820u, 0x0000000000000000ul, 0x0000000080000000ul, 0x0000000080000000ul)]
|
[TestCase(0x1E225820u, 0x0000000000000000ul, 0x0000000080000000ul, 0x0000000080000000ul)]
|
||||||
|
@ -85,6 +87,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
V1: Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, A)),
|
V1: Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, A)),
|
||||||
V2: Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, B)));
|
V2: Sse.StaticCast<ulong, float>(Sse2.SetVector128(0, B)));
|
||||||
Assert.AreEqual(Result, Sse41.Extract(Sse.StaticCast<float, ulong>(ThreadState.V0), 0));
|
Assert.AreEqual(Result, Sse41.Extract(Sse.StaticCast<float, ulong>(ThreadState.V0), 0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x80000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x80000000u)]
|
[TestCase(0x80000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x80000000u)]
|
||||||
|
@ -111,6 +114,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
||||||
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FMUL S6, S1, V0.S[2]")]
|
[Test, Description("FMUL S6, S1, V0.S[2]")]
|
||||||
|
@ -121,6 +125,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
V0: Sse.SetVector128(0, B, 0, 0));
|
V0: Sse.SetVector128(0, B, 0, 0));
|
||||||
|
|
||||||
Assert.That(Sse41.Extract(ThreadState.V6, (byte)0), Is.EqualTo(A * B));
|
Assert.That(Sse41.Extract(ThreadState.V6, (byte)0), Is.EqualTo(A * B));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x00000000u, 0x7F800000u)]
|
[TestCase(0x00000000u, 0x7F800000u)]
|
||||||
|
@ -135,6 +140,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Vector128<float> V1 = MakeVectorE0(A);
|
Vector128<float> V1 = MakeVectorE0(A);
|
||||||
AThreadState ThreadState = SingleOpcode(0x5EA1D820, V1: V1);
|
AThreadState ThreadState = SingleOpcode(0x5EA1D820, V1: V1);
|
||||||
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FRECPS D0, D1, D2")]
|
[Test, Description("FRECPS D0, D1, D2")]
|
||||||
|
@ -145,6 +151,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
V2: MakeVectorE0(B));
|
V2: MakeVectorE0(B));
|
||||||
|
|
||||||
Assert.That(VectorExtractDouble(ThreadState.V0, 0), Is.EqualTo(2 - (A * B)));
|
Assert.That(VectorExtractDouble(ThreadState.V0, 0), Is.EqualTo(2 - (A * B)));
|
||||||
|
//CompareAgainstUnicorn(); // Not accurate enough
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FRECPS V4.4S, V2.4S, V0.4S")]
|
[Test, Description("FRECPS V4.4S, V2.4S, V0.4S")]
|
||||||
|
@ -163,6 +170,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(Sse41.Extract(ThreadState.V4, (byte)2), Is.EqualTo(Result));
|
Assert.That(Sse41.Extract(ThreadState.V4, (byte)2), Is.EqualTo(Result));
|
||||||
Assert.That(Sse41.Extract(ThreadState.V4, (byte)3), Is.EqualTo(Result));
|
Assert.That(Sse41.Extract(ThreadState.V4, (byte)3), Is.EqualTo(Result));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x3FE66666u, false, 0x40000000u)]
|
[TestCase(0x3FE66666u, false, 0x40000000u)]
|
||||||
|
@ -213,6 +221,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Vector128<float> V1 = MakeVectorE0(A);
|
Vector128<float> V1 = MakeVectorE0(A);
|
||||||
AThreadState ThreadState = SingleOpcode(0x1E264020, V1: V1, Fpcr: FpcrTemp);
|
AThreadState ThreadState = SingleOpcode(0x1E264020, V1: V1, Fpcr: FpcrTemp);
|
||||||
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x6E618820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
[TestCase(0x6E618820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
||||||
|
@ -240,6 +249,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
||||||
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x3FE66666u, 'N', false, 0x40000000u)]
|
[TestCase(0x3FE66666u, 'N', false, 0x40000000u)]
|
||||||
|
@ -310,6 +320,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Vector128<float> V1 = MakeVectorE0(A);
|
Vector128<float> V1 = MakeVectorE0(A);
|
||||||
AThreadState ThreadState = SingleOpcode(0x1E27C020, V1: V1, Fpcr: FpcrTemp);
|
AThreadState ThreadState = SingleOpcode(0x1E27C020, V1: V1, Fpcr: FpcrTemp);
|
||||||
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x6EE19820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, 'N', false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
[TestCase(0x6EE19820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, 'N', false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
||||||
|
@ -376,6 +387,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
||||||
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x3FE66666u, false, 0x3F800000u)]
|
[TestCase(0x3FE66666u, false, 0x3F800000u)]
|
||||||
|
@ -426,6 +438,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Vector128<float> V1 = MakeVectorE0(A);
|
Vector128<float> V1 = MakeVectorE0(A);
|
||||||
AThreadState ThreadState = SingleOpcode(0x1E254020, V1: V1, Fpcr: FpcrTemp);
|
AThreadState ThreadState = SingleOpcode(0x1E254020, V1: V1, Fpcr: FpcrTemp);
|
||||||
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x4E619820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
[TestCase(0x4E619820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
||||||
|
@ -450,6 +463,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
||||||
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x3FE66666u, false, 0x40000000u)]
|
[TestCase(0x3FE66666u, false, 0x40000000u)]
|
||||||
|
@ -500,6 +514,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Vector128<float> V1 = MakeVectorE0(A);
|
Vector128<float> V1 = MakeVectorE0(A);
|
||||||
AThreadState ThreadState = SingleOpcode(0x1E264020, V1: V1, Fpcr: FpcrTemp);
|
AThreadState ThreadState = SingleOpcode(0x1E264020, V1: V1, Fpcr: FpcrTemp);
|
||||||
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x4E618820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
[TestCase(0x4E618820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
||||||
|
@ -527,6 +542,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
||||||
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x3FE66666u, false, 0x40000000u)]
|
[TestCase(0x3FE66666u, false, 0x40000000u)]
|
||||||
|
@ -577,6 +593,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Vector128<float> V1 = MakeVectorE0(A);
|
Vector128<float> V1 = MakeVectorE0(A);
|
||||||
AThreadState ThreadState = SingleOpcode(0x1E24C020, V1: V1, Fpcr: FpcrTemp);
|
AThreadState ThreadState = SingleOpcode(0x1E24C020, V1: V1, Fpcr: FpcrTemp);
|
||||||
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x4EE18820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, false, 0x4000000000000000ul, 0x4000000000000000ul)]
|
[TestCase(0x4EE18820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, false, 0x4000000000000000ul, 0x4000000000000000ul)]
|
||||||
|
@ -601,6 +618,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
||||||
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x3FE66666u, 'N', false, 0x40000000u)]
|
[TestCase(0x3FE66666u, 'N', false, 0x40000000u)]
|
||||||
|
@ -671,6 +689,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Vector128<float> V1 = MakeVectorE0(A);
|
Vector128<float> V1 = MakeVectorE0(A);
|
||||||
AThreadState ThreadState = SingleOpcode(0x1E274020, V1: V1, Fpcr: FpcrTemp);
|
AThreadState ThreadState = SingleOpcode(0x1E274020, V1: V1, Fpcr: FpcrTemp);
|
||||||
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x6E619820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, 'N', false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
[TestCase(0x6E619820u, 0x3FF3333333333333ul, 0x3FF3333333333333ul, 'N', false, 0x3FF0000000000000ul, 0x3FF0000000000000ul)]
|
||||||
|
@ -737,6 +756,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result0, GetVectorE0(ThreadState.V0));
|
||||||
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
Assert.AreEqual(Result1, GetVectorE1(ThreadState.V0));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0x41200000u, 0x3EA18000u)]
|
[TestCase(0x41200000u, 0x3EA18000u)]
|
||||||
|
@ -745,6 +765,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Vector128<float> V1 = MakeVectorE0(A);
|
Vector128<float> V1 = MakeVectorE0(A);
|
||||||
AThreadState ThreadState = SingleOpcode(0x7EA1D820, V1: V1);
|
AThreadState ThreadState = SingleOpcode(0x7EA1D820, V1: V1);
|
||||||
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
Assert.AreEqual(Result, GetVectorE0(ThreadState.V0));
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)0)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)0)), Is.EquivalentTo(Exp));
|
||||||
Assert.That(VectorExtractDouble(ThreadState.V0, (byte)1), Is.Zero);
|
Assert.That(VectorExtractDouble(ThreadState.V0, (byte)1), Is.Zero);
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FCMEQ S0, S1, S2 | FCMGE S0, S1, S2 | FCMGT S0, S1, S2")]
|
[Test, Description("FCMEQ S0, S1, S2 | FCMGE S0, S1, S2 | FCMGT S0, S1, S2")]
|
||||||
|
@ -84,6 +85,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(Sse41.Extract(ThreadState.V0, (byte)2), Is.Zero);
|
Assert.That(Sse41.Extract(ThreadState.V0, (byte)2), Is.Zero);
|
||||||
Assert.That(Sse41.Extract(ThreadState.V0, (byte)3), Is.Zero);
|
Assert.That(Sse41.Extract(ThreadState.V0, (byte)3), Is.Zero);
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FCMEQ V0.2D, V1.2D, V2.2D | FCMGE V0.2D, V1.2D, V2.2D | FCMGT V0.2D, V1.2D, V2.2D")]
|
[Test, Description("FCMEQ V0.2D, V1.2D, V2.2D | FCMGE V0.2D, V1.2D, V2.2D | FCMGT V0.2D, V1.2D, V2.2D")]
|
||||||
|
@ -113,6 +115,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)0)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)0)), Is.EquivalentTo(Exp));
|
||||||
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)1)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)1)), Is.EquivalentTo(Exp));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FCMEQ V0.2S, V1.2S, V2.2S | FCMGE V0.2S, V1.2S, V2.2S | FCMGT V0.2S, V1.2S, V2.2S")]
|
[Test, Description("FCMEQ V0.2S, V1.2S, V2.2S | FCMGE V0.2S, V1.2S, V2.2S | FCMGT V0.2S, V1.2S, V2.2S")]
|
||||||
|
@ -145,6 +148,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(Sse41.Extract(ThreadState.V0, (byte)2), Is.Zero);
|
Assert.That(Sse41.Extract(ThreadState.V0, (byte)2), Is.Zero);
|
||||||
Assert.That(Sse41.Extract(ThreadState.V0, (byte)3), Is.Zero);
|
Assert.That(Sse41.Extract(ThreadState.V0, (byte)3), Is.Zero);
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FCMEQ V0.4S, V1.4S, V2.4S | FCMGE V0.4S, V1.4S, V2.4S | FCMGT V0.4S, V1.4S, V2.4S")]
|
[Test, Description("FCMEQ V0.4S, V1.4S, V2.4S | FCMGE V0.4S, V1.4S, V2.4S | FCMGT V0.4S, V1.4S, V2.4S")]
|
||||||
|
@ -176,6 +180,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(BitConverter.GetBytes(Sse41.Extract(ThreadState.V0, (byte)2)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(Sse41.Extract(ThreadState.V0, (byte)2)), Is.EquivalentTo(Exp));
|
||||||
Assert.That(BitConverter.GetBytes(Sse41.Extract(ThreadState.V0, (byte)3)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(Sse41.Extract(ThreadState.V0, (byte)3)), Is.EquivalentTo(Exp));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FCMGT D0, D1, #0.0 | FCMGE D0, D1, #0.0 | FCMEQ D0, D1, #0.0 | FCMLE D0, D1, #0.0 | FCMLT D0, D1, #0.0")]
|
[Test, Description("FCMGT D0, D1, #0.0 | FCMGE D0, D1, #0.0 | FCMEQ D0, D1, #0.0 | FCMLE D0, D1, #0.0 | FCMLT D0, D1, #0.0")]
|
||||||
|
@ -214,6 +219,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)0)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)0)), Is.EquivalentTo(Exp));
|
||||||
Assert.That(VectorExtractDouble(ThreadState.V0, (byte)1), Is.Zero);
|
Assert.That(VectorExtractDouble(ThreadState.V0, (byte)1), Is.Zero);
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FCMGT S0, S1, #0.0 | FCMGE S0, S1, #0.0 | FCMEQ S0, S1, #0.0 | FCMLE S0, S1, #0.0 | FCMLT S0, S1, #0.0")]
|
[Test, Description("FCMGT S0, S1, #0.0 | FCMGE S0, S1, #0.0 | FCMEQ S0, S1, #0.0 | FCMLE S0, S1, #0.0 | FCMLT S0, S1, #0.0")]
|
||||||
|
@ -254,6 +260,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(Sse41.Extract(ThreadState.V0, (byte)2), Is.Zero);
|
Assert.That(Sse41.Extract(ThreadState.V0, (byte)2), Is.Zero);
|
||||||
Assert.That(Sse41.Extract(ThreadState.V0, (byte)3), Is.Zero);
|
Assert.That(Sse41.Extract(ThreadState.V0, (byte)3), Is.Zero);
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FCMGT V0.2D, V1.2D, #0.0 | FCMGE V0.2D, V1.2D, #0.0 | FCMEQ V0.2D, V1.2D, #0.0 | FCMLE V0.2D, V1.2D, #0.0 | FCMLT V0.2D, V1.2D, #0.0")]
|
[Test, Description("FCMGT V0.2D, V1.2D, #0.0 | FCMGE V0.2D, V1.2D, #0.0 | FCMEQ V0.2D, V1.2D, #0.0 | FCMLE V0.2D, V1.2D, #0.0 | FCMLT V0.2D, V1.2D, #0.0")]
|
||||||
|
@ -291,6 +298,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)0)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)0)), Is.EquivalentTo(Exp));
|
||||||
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)1)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(VectorExtractDouble(ThreadState.V0, (byte)1)), Is.EquivalentTo(Exp));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FCMGT V0.2S, V1.2S, #0.0 | FCMGE V0.2S, V1.2S, #0.0 | FCMEQ V0.2S, V1.2S, #0.0 | FCMLE V0.2S, V1.2S, #0.0 | FCMLT V0.2S, V1.2S, #0.0")]
|
[Test, Description("FCMGT V0.2S, V1.2S, #0.0 | FCMGE V0.2S, V1.2S, #0.0 | FCMEQ V0.2S, V1.2S, #0.0 | FCMLE V0.2S, V1.2S, #0.0 | FCMLT V0.2S, V1.2S, #0.0")]
|
||||||
|
@ -331,6 +339,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(Sse41.Extract(ThreadState.V0, (byte)2), Is.Zero);
|
Assert.That(Sse41.Extract(ThreadState.V0, (byte)2), Is.Zero);
|
||||||
Assert.That(Sse41.Extract(ThreadState.V0, (byte)3), Is.Zero);
|
Assert.That(Sse41.Extract(ThreadState.V0, (byte)3), Is.Zero);
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Description("FCMGT V0.4S, V1.4S, #0.0 | FCMGE V0.4S, V1.4S, #0.0 | FCMEQ V0.4S, V1.4S, #0.0 | FCMLE V0.4S, V1.4S, #0.0 | FCMLT V0.4S, V1.4S, #0.0")]
|
[Test, Description("FCMGT V0.4S, V1.4S, #0.0 | FCMGE V0.4S, V1.4S, #0.0 | FCMEQ V0.4S, V1.4S, #0.0 | FCMLE V0.4S, V1.4S, #0.0 | FCMLT V0.4S, V1.4S, #0.0")]
|
||||||
|
@ -370,6 +379,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(BitConverter.GetBytes(Sse41.Extract(ThreadState.V0, (byte)2)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(Sse41.Extract(ThreadState.V0, (byte)2)), Is.EquivalentTo(Exp));
|
||||||
Assert.That(BitConverter.GetBytes(Sse41.Extract(ThreadState.V0, (byte)3)), Is.EquivalentTo(Exp));
|
Assert.That(BitConverter.GetBytes(Sse41.Extract(ThreadState.V0, (byte)3)), Is.EquivalentTo(Exp));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
139
Ryujinx.Tests/Cpu/CpuTestSimdCrypto.cs
Normal file
139
Ryujinx.Tests/Cpu/CpuTestSimdCrypto.cs
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
|
||||||
|
|
||||||
|
using ChocolArm64.State;
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Cpu
|
||||||
|
{
|
||||||
|
public class CpuTestSimdCrypto : CpuTest
|
||||||
|
{
|
||||||
|
[Test, Description("AESD <Vd>.16B, <Vn>.16B")]
|
||||||
|
public void Aesd_V([Values(0u)] uint Rd,
|
||||||
|
[Values(1u)] uint Rn,
|
||||||
|
[Values(0x7B5B546573745665ul)] ulong ValueH,
|
||||||
|
[Values(0x63746F725D53475Dul)] ulong ValueL,
|
||||||
|
[Random(2)] ulong RoundKeyH,
|
||||||
|
[Random(2)] ulong RoundKeyL,
|
||||||
|
[Values(0x8DCAB9BC035006BCul)] ulong ResultH,
|
||||||
|
[Values(0x8F57161E00CAFD8Dul)] ulong ResultL)
|
||||||
|
{
|
||||||
|
uint Opcode = 0x4E285800; // AESD V0.16B, V0.16B
|
||||||
|
Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
|
||||||
|
Vector128<float> V0 = MakeVectorE0E1(RoundKeyL ^ ValueL, RoundKeyH ^ ValueH);
|
||||||
|
Vector128<float> V1 = MakeVectorE0E1(RoundKeyL, RoundKeyH);
|
||||||
|
|
||||||
|
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(ResultL));
|
||||||
|
Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(ResultH));
|
||||||
|
});
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(GetVectorE0(ThreadState.V1), Is.EqualTo(RoundKeyL));
|
||||||
|
Assert.That(GetVectorE1(ThreadState.V1), Is.EqualTo(RoundKeyH));
|
||||||
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Description("AESE <Vd>.16B, <Vn>.16B")]
|
||||||
|
public void Aese_V([Values(0u)] uint Rd,
|
||||||
|
[Values(1u)] uint Rn,
|
||||||
|
[Values(0x7B5B546573745665ul)] ulong ValueH,
|
||||||
|
[Values(0x63746F725D53475Dul)] ulong ValueL,
|
||||||
|
[Random(2)] ulong RoundKeyH,
|
||||||
|
[Random(2)] ulong RoundKeyL,
|
||||||
|
[Values(0x8F92A04DFBED204Dul)] ulong ResultH,
|
||||||
|
[Values(0x4C39B1402192A84Cul)] ulong ResultL)
|
||||||
|
{
|
||||||
|
uint Opcode = 0x4E284800; // AESE V0.16B, V0.16B
|
||||||
|
Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
|
||||||
|
Vector128<float> V0 = MakeVectorE0E1(RoundKeyL ^ ValueL, RoundKeyH ^ ValueH);
|
||||||
|
Vector128<float> V1 = MakeVectorE0E1(RoundKeyL, RoundKeyH);
|
||||||
|
|
||||||
|
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(ResultL));
|
||||||
|
Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(ResultH));
|
||||||
|
});
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(GetVectorE0(ThreadState.V1), Is.EqualTo(RoundKeyL));
|
||||||
|
Assert.That(GetVectorE1(ThreadState.V1), Is.EqualTo(RoundKeyH));
|
||||||
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Description("AESIMC <Vd>.16B, <Vn>.16B")]
|
||||||
|
public void Aesimc_V([Values(0u)] uint Rd,
|
||||||
|
[Values(1u, 0u)] uint Rn,
|
||||||
|
[Values(0x8DCAB9DC035006BCul)] ulong ValueH,
|
||||||
|
[Values(0x8F57161E00CAFD8Dul)] ulong ValueL,
|
||||||
|
[Values(0xD635A667928B5EAEul)] ulong ResultH,
|
||||||
|
[Values(0xEEC9CC3BC55F5777ul)] ulong ResultL)
|
||||||
|
{
|
||||||
|
uint Opcode = 0x4E287800; // AESIMC V0.16B, V0.16B
|
||||||
|
Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
|
||||||
|
Vector128<float> V = MakeVectorE0E1(ValueL, ValueH);
|
||||||
|
|
||||||
|
AThreadState ThreadState = SingleOpcode(
|
||||||
|
Opcode,
|
||||||
|
V0: Rn == 0u ? V : default(Vector128<float>),
|
||||||
|
V1: Rn == 1u ? V : default(Vector128<float>));
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(ResultL));
|
||||||
|
Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(ResultH));
|
||||||
|
});
|
||||||
|
if (Rn == 1u)
|
||||||
|
{
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(GetVectorE0(ThreadState.V1), Is.EqualTo(ValueL));
|
||||||
|
Assert.That(GetVectorE1(ThreadState.V1), Is.EqualTo(ValueH));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Description("AESMC <Vd>.16B, <Vn>.16B")]
|
||||||
|
public void Aesmc_V([Values(0u)] uint Rd,
|
||||||
|
[Values(1u, 0u)] uint Rn,
|
||||||
|
[Values(0x627A6F6644B109C8ul)] ulong ValueH,
|
||||||
|
[Values(0x2B18330A81C3B3E5ul)] ulong ValueL,
|
||||||
|
[Values(0x7B5B546573745665ul)] ulong ResultH,
|
||||||
|
[Values(0x63746F725D53475Dul)] ulong ResultL)
|
||||||
|
{
|
||||||
|
uint Opcode = 0x4E286800; // AESMC V0.16B, V0.16B
|
||||||
|
Opcode |= ((Rn & 31) << 5) | ((Rd & 31) << 0);
|
||||||
|
Vector128<float> V = MakeVectorE0E1(ValueL, ValueH);
|
||||||
|
|
||||||
|
AThreadState ThreadState = SingleOpcode(
|
||||||
|
Opcode,
|
||||||
|
V0: Rn == 0u ? V : default(Vector128<float>),
|
||||||
|
V1: Rn == 1u ? V : default(Vector128<float>));
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(GetVectorE0(ThreadState.V0), Is.EqualTo(ResultL));
|
||||||
|
Assert.That(GetVectorE1(ThreadState.V0), Is.EqualTo(ResultH));
|
||||||
|
});
|
||||||
|
if (Rn == 1u)
|
||||||
|
{
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(GetVectorE0(ThreadState.V1), Is.EqualTo(ValueL));
|
||||||
|
Assert.That(GetVectorE1(ThreadState.V1), Is.EqualTo(ValueH));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,7 @@ namespace Ryujinx.Tests.Cpu
|
||||||
Assert.That(Sse41.Extract(Sse.StaticCast<float, uint>(ThreadState.V1), (byte)2), Is.EqualTo(Result));
|
Assert.That(Sse41.Extract(Sse.StaticCast<float, uint>(ThreadState.V1), (byte)2), Is.EqualTo(Result));
|
||||||
Assert.That(Sse41.Extract(Sse.StaticCast<float, uint>(ThreadState.V1), (byte)3), Is.EqualTo(Result));
|
Assert.That(Sse41.Extract(Sse.StaticCast<float, uint>(ThreadState.V1), (byte)3), Is.EqualTo(Result));
|
||||||
});
|
});
|
||||||
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2685,6 +2685,154 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
V(d, result);
|
V(d, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fcvtns_advsimd.html#FCVTNS_asisdmisc_R
|
||||||
|
public static void Fcvtns_S(Bits sz, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = false;
|
||||||
|
const bool o2 = false;
|
||||||
|
const bool o1 = false;
|
||||||
|
|
||||||
|
/* Decode Scalar */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
|
||||||
|
int esize = 32 << (int)UInt(sz);
|
||||||
|
int datasize = esize;
|
||||||
|
int elements = 1;
|
||||||
|
|
||||||
|
FPRounding rounding = FPDecodeRounding(Bits.Concat(o1, o2));
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand = V(datasize, n);
|
||||||
|
Bits element;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element = Elem(operand, e, esize);
|
||||||
|
|
||||||
|
Elem(result, e, esize, FPToFixed(esize, element, 0, unsigned, FPCR, rounding));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fcvtns_advsimd.html#FCVTNS_asimdmisc_R
|
||||||
|
public static void Fcvtns_V(bool Q, Bits sz, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = false;
|
||||||
|
const bool o2 = false;
|
||||||
|
const bool o1 = false;
|
||||||
|
|
||||||
|
/* Decode Vector */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
|
||||||
|
/* if sz:Q == '10' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 32 << (int)UInt(sz);
|
||||||
|
int datasize = (Q ? 128 : 64);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
FPRounding rounding = FPDecodeRounding(Bits.Concat(o1, o2));
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand = V(datasize, n);
|
||||||
|
Bits element;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element = Elem(operand, e, esize);
|
||||||
|
|
||||||
|
Elem(result, e, esize, FPToFixed(esize, element, 0, unsigned, FPCR, rounding));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fcvtnu_advsimd.html#FCVTNU_asisdmisc_R
|
||||||
|
public static void Fcvtnu_S(Bits sz, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = true;
|
||||||
|
const bool o2 = false;
|
||||||
|
const bool o1 = false;
|
||||||
|
|
||||||
|
/* Decode Scalar */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
|
||||||
|
int esize = 32 << (int)UInt(sz);
|
||||||
|
int datasize = esize;
|
||||||
|
int elements = 1;
|
||||||
|
|
||||||
|
FPRounding rounding = FPDecodeRounding(Bits.Concat(o1, o2));
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand = V(datasize, n);
|
||||||
|
Bits element;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element = Elem(operand, e, esize);
|
||||||
|
|
||||||
|
Elem(result, e, esize, FPToFixed(esize, element, 0, unsigned, FPCR, rounding));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fcvtnu_advsimd.html#FCVTNU_asimdmisc_R
|
||||||
|
public static void Fcvtnu_V(bool Q, Bits sz, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = true;
|
||||||
|
const bool o2 = false;
|
||||||
|
const bool o1 = false;
|
||||||
|
|
||||||
|
/* Decode Vector */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
|
||||||
|
/* if sz:Q == '10' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 32 << (int)UInt(sz);
|
||||||
|
int datasize = (Q ? 128 : 64);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
FPRounding rounding = FPDecodeRounding(Bits.Concat(o1, o2));
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand = V(datasize, n);
|
||||||
|
Bits element;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element = Elem(operand, e, esize);
|
||||||
|
|
||||||
|
Elem(result, e, esize, FPToFixed(esize, element, 0, unsigned, FPCR, rounding));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
// neg_advsimd.html#NEG_asisdmisc_R
|
// neg_advsimd.html#NEG_asisdmisc_R
|
||||||
public static void Neg_S(Bits size, Bits Rn, Bits Rd)
|
public static void Neg_S(Bits size, Bits Rn, Bits Rd)
|
||||||
{
|
{
|
||||||
|
@ -5122,6 +5270,57 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
V(d, result);
|
V(d, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// saddl_advsimd.html
|
||||||
|
public static void Saddl_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = false;
|
||||||
|
const bool o1 = false;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = 64;
|
||||||
|
int part = (int)UInt(Q);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool sub_op = (o1 == true);
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(2 * datasize);
|
||||||
|
Bits operand1 = Vpart(datasize, n, part);
|
||||||
|
Bits operand2 = Vpart(datasize, m, part);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
BigInteger sum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
if (sub_op)
|
||||||
|
{
|
||||||
|
sum = element1 - element2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sum = element1 + element2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elem(result, e, 2 * esize, sum.SubBigInteger(2 * esize - 1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
// saddw_advsimd.html
|
// saddw_advsimd.html
|
||||||
public static void Saddw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
public static void Saddw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
{
|
{
|
||||||
|
@ -5251,6 +5450,198 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
V(d, result);
|
V(d, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shadd_advsimd.html
|
||||||
|
public static void Shadd_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = false;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = (Q ? 128 : 64);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand1 = V(datasize, n);
|
||||||
|
Bits operand2 = V(datasize, m);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
BigInteger sum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
sum = element1 + element2;
|
||||||
|
|
||||||
|
Elem(result, e, esize, sum.SubBigInteger(esize, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// shsub_advsimd.html
|
||||||
|
public static void Shsub_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = false;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = (Q ? 128 : 64);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand1 = V(datasize, n);
|
||||||
|
Bits operand2 = V(datasize, m);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
BigInteger diff;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
diff = element1 - element2;
|
||||||
|
|
||||||
|
Elem(result, e, esize, diff.SubBigInteger(esize, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// smlal_advsimd_vec.html
|
||||||
|
public static void Smlal_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = false;
|
||||||
|
const bool o1 = false;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = 64;
|
||||||
|
int part = (int)UInt(Q);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool sub_op = (o1 == true);
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(2 * datasize);
|
||||||
|
Bits operand1 = Vpart(datasize, n, part);
|
||||||
|
Bits operand2 = Vpart(datasize, m, part);
|
||||||
|
Bits operand3 = V(2 * datasize, d);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
Bits product;
|
||||||
|
Bits accum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
product = (element1 * element2).SubBigInteger(2 * esize - 1, 0);
|
||||||
|
|
||||||
|
if (sub_op)
|
||||||
|
{
|
||||||
|
accum = Elem(operand3, e, 2 * esize) - product;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
accum = Elem(operand3, e, 2 * esize) + product;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elem(result, e, 2 * esize, accum);
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// smlsl_advsimd_vec.html
|
||||||
|
public static void Smlsl_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = false;
|
||||||
|
const bool o1 = true;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = 64;
|
||||||
|
int part = (int)UInt(Q);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool sub_op = (o1 == true);
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(2 * datasize);
|
||||||
|
Bits operand1 = Vpart(datasize, n, part);
|
||||||
|
Bits operand2 = Vpart(datasize, m, part);
|
||||||
|
Bits operand3 = V(2 * datasize, d);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
Bits product;
|
||||||
|
Bits accum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
product = (element1 * element2).SubBigInteger(2 * esize - 1, 0);
|
||||||
|
|
||||||
|
if (sub_op)
|
||||||
|
{
|
||||||
|
accum = Elem(operand3, e, 2 * esize) - product;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
accum = Elem(operand3, e, 2 * esize) + product;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elem(result, e, 2 * esize, accum);
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
// sqadd_advsimd.html#SQADD_asisdsame_only
|
// sqadd_advsimd.html#SQADD_asisdsame_only
|
||||||
public static void Sqadd_S(Bits size, Bits Rm, Bits Rn, Bits Rd)
|
public static void Sqadd_S(Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
{
|
{
|
||||||
|
@ -5651,6 +6042,95 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
V(d, result);
|
V(d, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// srhadd_advsimd.html
|
||||||
|
public static void Srhadd_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = false;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = (Q ? 128 : 64);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand1 = V(datasize, n);
|
||||||
|
Bits operand2 = V(datasize, m);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
Elem(result, e, esize, (element1 + element2 + 1).SubBigInteger(esize, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ssubl_advsimd.html
|
||||||
|
public static void Ssubl_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = false;
|
||||||
|
const bool o1 = true;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = 64;
|
||||||
|
int part = (int)UInt(Q);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool sub_op = (o1 == true);
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(2 * datasize);
|
||||||
|
Bits operand1 = Vpart(datasize, n, part);
|
||||||
|
Bits operand2 = Vpart(datasize, m, part);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
BigInteger sum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
if (sub_op)
|
||||||
|
{
|
||||||
|
sum = element1 - element2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sum = element1 + element2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elem(result, e, 2 * esize, sum.SubBigInteger(2 * esize - 1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
// ssubw_advsimd.html
|
// ssubw_advsimd.html
|
||||||
public static void Ssubw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
public static void Ssubw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
{
|
{
|
||||||
|
@ -6092,6 +6572,57 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
V(d, result);
|
V(d, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// uaddl_advsimd.html
|
||||||
|
public static void Uaddl_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = true;
|
||||||
|
const bool o1 = false;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = 64;
|
||||||
|
int part = (int)UInt(Q);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool sub_op = (o1 == true);
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(2 * datasize);
|
||||||
|
Bits operand1 = Vpart(datasize, n, part);
|
||||||
|
Bits operand2 = Vpart(datasize, m, part);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
BigInteger sum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
if (sub_op)
|
||||||
|
{
|
||||||
|
sum = element1 - element2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sum = element1 + element2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elem(result, e, 2 * esize, sum.SubBigInteger(2 * esize - 1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
// uaddw_advsimd.html
|
// uaddw_advsimd.html
|
||||||
public static void Uaddw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
public static void Uaddw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
{
|
{
|
||||||
|
@ -6143,6 +6674,198 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
V(d, result);
|
V(d, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// uhadd_advsimd.html
|
||||||
|
public static void Uhadd_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = true;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = (Q ? 128 : 64);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand1 = V(datasize, n);
|
||||||
|
Bits operand2 = V(datasize, m);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
BigInteger sum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
sum = element1 + element2;
|
||||||
|
|
||||||
|
Elem(result, e, esize, sum.SubBigInteger(esize, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// uhsub_advsimd.html
|
||||||
|
public static void Uhsub_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = true;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = (Q ? 128 : 64);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand1 = V(datasize, n);
|
||||||
|
Bits operand2 = V(datasize, m);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
BigInteger diff;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
diff = element1 - element2;
|
||||||
|
|
||||||
|
Elem(result, e, esize, diff.SubBigInteger(esize, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// umlal_advsimd_vec.html
|
||||||
|
public static void Umlal_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = true;
|
||||||
|
const bool o1 = false;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = 64;
|
||||||
|
int part = (int)UInt(Q);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool sub_op = (o1 == true);
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(2 * datasize);
|
||||||
|
Bits operand1 = Vpart(datasize, n, part);
|
||||||
|
Bits operand2 = Vpart(datasize, m, part);
|
||||||
|
Bits operand3 = V(2 * datasize, d);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
Bits product;
|
||||||
|
Bits accum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
product = (element1 * element2).SubBigInteger(2 * esize - 1, 0);
|
||||||
|
|
||||||
|
if (sub_op)
|
||||||
|
{
|
||||||
|
accum = Elem(operand3, e, 2 * esize) - product;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
accum = Elem(operand3, e, 2 * esize) + product;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elem(result, e, 2 * esize, accum);
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// umlsl_advsimd_vec.html
|
||||||
|
public static void Umlsl_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = true;
|
||||||
|
const bool o1 = true;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = 64;
|
||||||
|
int part = (int)UInt(Q);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool sub_op = (o1 == true);
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(2 * datasize);
|
||||||
|
Bits operand1 = Vpart(datasize, n, part);
|
||||||
|
Bits operand2 = Vpart(datasize, m, part);
|
||||||
|
Bits operand3 = V(2 * datasize, d);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
Bits product;
|
||||||
|
Bits accum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
product = (element1 * element2).SubBigInteger(2 * esize - 1, 0);
|
||||||
|
|
||||||
|
if (sub_op)
|
||||||
|
{
|
||||||
|
accum = Elem(operand3, e, 2 * esize) - product;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
accum = Elem(operand3, e, 2 * esize) + product;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elem(result, e, 2 * esize, accum);
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
// uqadd_advsimd.html#UQADD_asisdsame_only
|
// uqadd_advsimd.html#UQADD_asisdsame_only
|
||||||
public static void Uqadd_S(Bits size, Bits Rm, Bits Rn, Bits Rd)
|
public static void Uqadd_S(Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
{
|
{
|
||||||
|
@ -6339,6 +7062,95 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
V(d, result);
|
V(d, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// urhadd_advsimd.html
|
||||||
|
public static void Urhadd_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = true;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = (Q ? 128 : 64);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(datasize);
|
||||||
|
Bits operand1 = V(datasize, n);
|
||||||
|
Bits operand2 = V(datasize, m);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
Elem(result, e, esize, (element1 + element2 + 1).SubBigInteger(esize, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// usubl_advsimd.html
|
||||||
|
public static void Usubl_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
|
{
|
||||||
|
const bool U = true;
|
||||||
|
const bool o1 = true;
|
||||||
|
|
||||||
|
/* Decode */
|
||||||
|
int d = (int)UInt(Rd);
|
||||||
|
int n = (int)UInt(Rn);
|
||||||
|
int m = (int)UInt(Rm);
|
||||||
|
|
||||||
|
/* if size == '11' then ReservedValue(); */
|
||||||
|
|
||||||
|
int esize = 8 << (int)UInt(size);
|
||||||
|
int datasize = 64;
|
||||||
|
int part = (int)UInt(Q);
|
||||||
|
int elements = datasize / esize;
|
||||||
|
|
||||||
|
bool sub_op = (o1 == true);
|
||||||
|
bool unsigned = (U == true);
|
||||||
|
|
||||||
|
/* Operation */
|
||||||
|
/* CheckFPAdvSIMDEnabled64(); */
|
||||||
|
|
||||||
|
Bits result = new Bits(2 * datasize);
|
||||||
|
Bits operand1 = Vpart(datasize, n, part);
|
||||||
|
Bits operand2 = Vpart(datasize, m, part);
|
||||||
|
BigInteger element1;
|
||||||
|
BigInteger element2;
|
||||||
|
BigInteger sum;
|
||||||
|
|
||||||
|
for (int e = 0; e <= elements - 1; e++)
|
||||||
|
{
|
||||||
|
element1 = Int(Elem(operand1, e, esize), unsigned);
|
||||||
|
element2 = Int(Elem(operand2, e, esize), unsigned);
|
||||||
|
|
||||||
|
if (sub_op)
|
||||||
|
{
|
||||||
|
sum = element1 - element2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sum = element1 + element2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elem(result, e, 2 * esize, sum.SubBigInteger(2 * esize - 1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
V(d, result);
|
||||||
|
}
|
||||||
|
|
||||||
// usubw_advsimd.html
|
// usubw_advsimd.html
|
||||||
public static void Usubw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
public static void Usubw_V(bool Q, Bits size, Bits Rm, Bits Rn, Bits Rd)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,21 +5,19 @@
|
||||||
|
|
||||||
// https://alastairreid.github.io/asl-lexical-syntax/
|
// https://alastairreid.github.io/asl-lexical-syntax/
|
||||||
|
|
||||||
// | ------------------------|----------------------------------- |
|
// | ------------------------|-------------------------------- |
|
||||||
// | ASL | C# |
|
// | ASL | C# |
|
||||||
// | ------------------------|----------------------------------- |
|
// | ------------------------|-------------------------------- |
|
||||||
// | bit, bits(1); boolean | bool |
|
// | bit, bits(1); boolean | bool |
|
||||||
// | bits | Bits |
|
// | bits | Bits |
|
||||||
// | integer | BigInteger, int |
|
// | integer | BigInteger, int |
|
||||||
// | real | decimal |
|
// | real | decimal; double, float |
|
||||||
// | ------------------------|----------------------------------- |
|
// | ------------------------|-------------------------------- |
|
||||||
// | '0'; FALSE | false |
|
// | '0'; FALSE | false |
|
||||||
// | '1'; TRUE | true |
|
// | '1'; TRUE | true |
|
||||||
// | '010' | "010" |
|
// | '010' | "010" |
|
||||||
// | bitsX IN {bitsY, bitsZ} | (bitsX == bitsY || bitsX == bitsZ) |
|
// | DIV, MOD | /, % |
|
||||||
// | DIV | / |
|
// | ------------------------|-------------------------------- |
|
||||||
// | MOD | % |
|
|
||||||
// | ------------------------|----------------------------------- |
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
@ -107,6 +105,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
/* SP_EL1 = bits(64) UNKNOWN; */
|
/* SP_EL1 = bits(64) UNKNOWN; */
|
||||||
SP_EL1.SetAll(false);
|
SP_EL1.SetAll(false);
|
||||||
|
|
||||||
|
FPCR.SetAll(false); // TODO: Add named fields.
|
||||||
FPSR.SetAll(false); // TODO: Add named fields.
|
FPSR.SetAll(false); // TODO: Add named fields.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,6 +457,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "instrs/vector/reduce/reduceop/"
|
#region "instrs/vector/reduce/reduceop/"
|
||||||
|
// shared_pseudocode.html#impl-aarch64.Reduce.3
|
||||||
public static Bits Reduce(ReduceOp op, Bits input, int esize)
|
public static Bits Reduce(ReduceOp op, Bits input, int esize)
|
||||||
{
|
{
|
||||||
int N = input.Count;
|
int N = input.Count;
|
||||||
|
@ -528,6 +528,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
SP_EL0 = new Bits(64, false);
|
SP_EL0 = new Bits(64, false);
|
||||||
SP_EL1 = new Bits(64, false);
|
SP_EL1 = new Bits(64, false);
|
||||||
|
|
||||||
|
FPCR = new Bits(32, false); // TODO: Add named fields.
|
||||||
FPSR = new Bits(32, false); // TODO: Add named fields.
|
FPSR = new Bits(32, false); // TODO: Add named fields.
|
||||||
|
|
||||||
PSTATE.N = false;
|
PSTATE.N = false;
|
||||||
|
@ -817,6 +818,36 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
return (decimal)value;
|
return (decimal)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
public static float Real_32(BigInteger value)
|
||||||
|
{
|
||||||
|
if (value == BigInteger.Pow((BigInteger)2.0f, 1000))
|
||||||
|
{
|
||||||
|
return float.PositiveInfinity;
|
||||||
|
}
|
||||||
|
if (value == -BigInteger.Pow((BigInteger)2.0f, 1000))
|
||||||
|
{
|
||||||
|
return float.NegativeInfinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
public static double Real_64(BigInteger value)
|
||||||
|
{
|
||||||
|
if (value == BigInteger.Pow((BigInteger)2.0, 10000))
|
||||||
|
{
|
||||||
|
return double.PositiveInfinity;
|
||||||
|
}
|
||||||
|
if (value == -BigInteger.Pow((BigInteger)2.0, 10000))
|
||||||
|
{
|
||||||
|
return double.NegativeInfinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (double)value;
|
||||||
|
}
|
||||||
|
|
||||||
// shared_pseudocode.html#impl-shared.ROR.2
|
// shared_pseudocode.html#impl-shared.ROR.2
|
||||||
public static Bits ROR(Bits x, int shift)
|
public static Bits ROR(Bits x, int shift)
|
||||||
{
|
{
|
||||||
|
@ -881,6 +912,36 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
return (BigInteger)Decimal.Floor(x);
|
return (BigInteger)Decimal.Floor(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
public static BigInteger RoundDown_32(float x)
|
||||||
|
{
|
||||||
|
if (float.IsPositiveInfinity(x))
|
||||||
|
{
|
||||||
|
return BigInteger.Pow((BigInteger)2.0f, 1000);
|
||||||
|
}
|
||||||
|
if (float.IsNegativeInfinity(x))
|
||||||
|
{
|
||||||
|
return -BigInteger.Pow((BigInteger)2.0f, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (BigInteger)MathF.Floor(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
public static BigInteger RoundDown_64(double x)
|
||||||
|
{
|
||||||
|
if (double.IsPositiveInfinity(x))
|
||||||
|
{
|
||||||
|
return BigInteger.Pow((BigInteger)2.0, 10000);
|
||||||
|
}
|
||||||
|
if (double.IsNegativeInfinity(x))
|
||||||
|
{
|
||||||
|
return -BigInteger.Pow((BigInteger)2.0, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (BigInteger)Math.Floor(x);
|
||||||
|
}
|
||||||
|
|
||||||
// shared_pseudocode.html#impl-shared.RoundTowardsZero.1
|
// shared_pseudocode.html#impl-shared.RoundTowardsZero.1
|
||||||
public static BigInteger RoundTowardsZero(decimal x)
|
public static BigInteger RoundTowardsZero(decimal x)
|
||||||
{
|
{
|
||||||
|
@ -1091,6 +1152,398 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region "functions/float/fpdecoderounding/"
|
||||||
|
/* shared_pseudocode.html#impl-shared.FPDecodeRounding.1 */
|
||||||
|
public static FPRounding FPDecodeRounding(Bits rmode)
|
||||||
|
{
|
||||||
|
switch (rmode)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case Bits bits when bits == "00":
|
||||||
|
return FPRounding.FPRounding_TIEEVEN; // N
|
||||||
|
case Bits bits when bits == "01":
|
||||||
|
return FPRounding.FPRounding_POSINF; // P
|
||||||
|
case Bits bits when bits == "10":
|
||||||
|
return FPRounding.FPRounding_NEGINF; // M
|
||||||
|
case Bits bits when bits == "11":
|
||||||
|
return FPRounding.FPRounding_ZERO; // Z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "functions/float/fpexc/"
|
||||||
|
// shared_pseudocode.html#FPExc
|
||||||
|
public enum FPExc {FPExc_InvalidOp, FPExc_DivideByZero, FPExc_Overflow,
|
||||||
|
FPExc_Underflow, FPExc_Inexact, FPExc_InputDenorm};
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "functions/float/fpprocessexception/"
|
||||||
|
// shared_pseudocode.html#impl-shared.FPProcessException.2
|
||||||
|
public static void FPProcessException(FPExc exception, Bits _fpcr)
|
||||||
|
{
|
||||||
|
Bits fpcr = new Bits(_fpcr); // Clone.
|
||||||
|
|
||||||
|
int cumul;
|
||||||
|
|
||||||
|
// Determine the cumulative exception bit number
|
||||||
|
switch (exception)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case FPExc.FPExc_InvalidOp: cumul = 0; break;
|
||||||
|
case FPExc.FPExc_DivideByZero: cumul = 1; break;
|
||||||
|
case FPExc.FPExc_Overflow: cumul = 2; break;
|
||||||
|
case FPExc.FPExc_Underflow: cumul = 3; break;
|
||||||
|
case FPExc.FPExc_Inexact: cumul = 4; break;
|
||||||
|
case FPExc.FPExc_InputDenorm: cumul = 7; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int enable = cumul + 8;
|
||||||
|
|
||||||
|
if (fpcr[enable])
|
||||||
|
{
|
||||||
|
// Trapping of the exception enabled.
|
||||||
|
// It is IMPLEMENTATION DEFINED whether the enable bit may be set at all, and
|
||||||
|
// if so then how exceptions may be accumulated before calling FPTrapException()
|
||||||
|
/* IMPLEMENTATION_DEFINED "floating-point trap handling"; */
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}/*
|
||||||
|
else if (UsingAArch32())
|
||||||
|
{
|
||||||
|
// Set the cumulative exception bit
|
||||||
|
FPSCR<cumul> = '1';
|
||||||
|
}*/
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Set the cumulative exception bit
|
||||||
|
FPSR[cumul] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "functions/float/fprounding/"
|
||||||
|
// shared_pseudocode.html#FPRounding
|
||||||
|
public enum FPRounding {FPRounding_TIEEVEN, FPRounding_POSINF,
|
||||||
|
FPRounding_NEGINF, FPRounding_ZERO,
|
||||||
|
FPRounding_TIEAWAY, FPRounding_ODD};
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "functions/float/fptofixed/"
|
||||||
|
/* shared_pseudocode.html#impl-shared.FPToFixed.5 */
|
||||||
|
public static Bits FPToFixed(int M, Bits op, int fbits, bool unsigned, Bits _fpcr, FPRounding rounding)
|
||||||
|
{
|
||||||
|
int N = op.Count;
|
||||||
|
|
||||||
|
/* assert N IN {16,32,64}; */
|
||||||
|
/* assert M IN {16,32,64}; */
|
||||||
|
/* assert fbits >= 0; */
|
||||||
|
/* assert rounding != FPRounding_ODD; */
|
||||||
|
|
||||||
|
Bits fpcr = new Bits(_fpcr); // Clone.
|
||||||
|
|
||||||
|
if (N == 16)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
else if (N == 32)
|
||||||
|
{
|
||||||
|
// Unpack using fpcr to determine if subnormals are flushed-to-zero
|
||||||
|
(FPType type, bool sign, float value) = FPUnpack_32(op, fpcr);
|
||||||
|
|
||||||
|
// If NaN, set cumulative flag or take exception
|
||||||
|
if (type == FPType.FPType_SNaN || type == FPType.FPType_QNaN)
|
||||||
|
{
|
||||||
|
FPProcessException(FPExc.FPExc_InvalidOp, fpcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale by fractional bits and produce integer rounded towards minus-infinity
|
||||||
|
value = value * MathF.Pow(2.0f, fbits);
|
||||||
|
BigInteger int_result = RoundDown_32(value);
|
||||||
|
float error = value - Real_32(int_result);
|
||||||
|
|
||||||
|
if (float.IsNaN(error))
|
||||||
|
{
|
||||||
|
error = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine whether supplied rounding mode requires an increment
|
||||||
|
bool round_up;
|
||||||
|
|
||||||
|
switch (rounding)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case FPRounding.FPRounding_TIEEVEN:
|
||||||
|
round_up = (error > 0.5f || (error == 0.5f && int_result.SubBigInteger(0)));
|
||||||
|
break;
|
||||||
|
case FPRounding.FPRounding_POSINF:
|
||||||
|
round_up = (error != 0.0f);
|
||||||
|
break;
|
||||||
|
case FPRounding.FPRounding_NEGINF:
|
||||||
|
round_up = false;
|
||||||
|
break;
|
||||||
|
case FPRounding.FPRounding_ZERO:
|
||||||
|
round_up = (error != 0.0f && int_result < (BigInteger)0);
|
||||||
|
break;
|
||||||
|
case FPRounding.FPRounding_TIEAWAY:
|
||||||
|
round_up = (error > 0.5f || (error == 0.5f && int_result >= (BigInteger)0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (round_up)
|
||||||
|
{
|
||||||
|
int_result = int_result + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate saturated result and exceptions
|
||||||
|
(Bits result, bool overflow) = SatQ(int_result, M, unsigned);
|
||||||
|
|
||||||
|
if (overflow)
|
||||||
|
{
|
||||||
|
FPProcessException(FPExc.FPExc_InvalidOp, fpcr);
|
||||||
|
}
|
||||||
|
else if (error != 0.0f)
|
||||||
|
{
|
||||||
|
FPProcessException(FPExc.FPExc_Inexact, fpcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else /* if (N == 64) */
|
||||||
|
{
|
||||||
|
// Unpack using fpcr to determine if subnormals are flushed-to-zero
|
||||||
|
(FPType type, bool sign, double value) = FPUnpack_64(op, fpcr);
|
||||||
|
|
||||||
|
// If NaN, set cumulative flag or take exception
|
||||||
|
if (type == FPType.FPType_SNaN || type == FPType.FPType_QNaN)
|
||||||
|
{
|
||||||
|
FPProcessException(FPExc.FPExc_InvalidOp, fpcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale by fractional bits and produce integer rounded towards minus-infinity
|
||||||
|
value = value * Math.Pow(2.0, fbits);
|
||||||
|
BigInteger int_result = RoundDown_64(value);
|
||||||
|
double error = value - Real_64(int_result);
|
||||||
|
|
||||||
|
if (double.IsNaN(error))
|
||||||
|
{
|
||||||
|
error = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine whether supplied rounding mode requires an increment
|
||||||
|
bool round_up;
|
||||||
|
|
||||||
|
switch (rounding)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case FPRounding.FPRounding_TIEEVEN:
|
||||||
|
round_up = (error > 0.5 || (error == 0.5 && int_result.SubBigInteger(0)));
|
||||||
|
break;
|
||||||
|
case FPRounding.FPRounding_POSINF:
|
||||||
|
round_up = (error != 0.0);
|
||||||
|
break;
|
||||||
|
case FPRounding.FPRounding_NEGINF:
|
||||||
|
round_up = false;
|
||||||
|
break;
|
||||||
|
case FPRounding.FPRounding_ZERO:
|
||||||
|
round_up = (error != 0.0 && int_result < (BigInteger)0);
|
||||||
|
break;
|
||||||
|
case FPRounding.FPRounding_TIEAWAY:
|
||||||
|
round_up = (error > 0.5 || (error == 0.5 && int_result >= (BigInteger)0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (round_up)
|
||||||
|
{
|
||||||
|
int_result = int_result + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate saturated result and exceptions
|
||||||
|
(Bits result, bool overflow) = SatQ(int_result, M, unsigned);
|
||||||
|
|
||||||
|
if (overflow)
|
||||||
|
{
|
||||||
|
FPProcessException(FPExc.FPExc_InvalidOp, fpcr);
|
||||||
|
}
|
||||||
|
else if (error != 0.0)
|
||||||
|
{
|
||||||
|
FPProcessException(FPExc.FPExc_Inexact, fpcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "functions/float/fptype/"
|
||||||
|
// shared_pseudocode.html#FPType
|
||||||
|
public enum FPType {FPType_Nonzero, FPType_Zero, FPType_Infinity,
|
||||||
|
FPType_QNaN, FPType_SNaN};
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "functions/float/fpunpack/"
|
||||||
|
/* shared_pseudocode.html#impl-shared.FPUnpack.2 */
|
||||||
|
/* shared_pseudocode.html#impl-shared.FPUnpackBase.2 */
|
||||||
|
/*public static (FPType, bool, real) FPUnpack_16(Bits fpval, Bits _fpcr)
|
||||||
|
{
|
||||||
|
int N = fpval.Count;
|
||||||
|
|
||||||
|
// assert N == 16;
|
||||||
|
|
||||||
|
Bits fpcr = new Bits(_fpcr); // Clone.
|
||||||
|
|
||||||
|
fpcr[26] = false;
|
||||||
|
|
||||||
|
return FPUnpackBase_16(fpval, fpcr);
|
||||||
|
}*/
|
||||||
|
public static (FPType, bool, float) FPUnpack_32(Bits fpval, Bits _fpcr)
|
||||||
|
{
|
||||||
|
int N = fpval.Count;
|
||||||
|
|
||||||
|
/* assert N == 32; */
|
||||||
|
|
||||||
|
Bits fpcr = new Bits(_fpcr); // Clone.
|
||||||
|
|
||||||
|
FPType type;
|
||||||
|
float value;
|
||||||
|
|
||||||
|
bool sign = fpval[31];
|
||||||
|
Bits exp32 = fpval[30, 23];
|
||||||
|
Bits frac32 = fpval[22, 0];
|
||||||
|
|
||||||
|
if (IsZero(exp32))
|
||||||
|
{
|
||||||
|
// Produce zero if value is zero or flush-to-zero is selected.
|
||||||
|
if (IsZero(frac32) || fpcr[24])
|
||||||
|
{
|
||||||
|
type = FPType.FPType_Zero;
|
||||||
|
value = 0.0f;
|
||||||
|
|
||||||
|
// Denormalized input flushed to zero
|
||||||
|
if (!IsZero(frac32))
|
||||||
|
{
|
||||||
|
FPProcessException(FPExc.FPExc_InputDenorm, fpcr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.FPType_Nonzero;
|
||||||
|
value = MathF.Pow(2.0f, -126) * (Real_32(UInt(frac32)) * MathF.Pow(2.0f, -23));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (IsOnes(exp32))
|
||||||
|
{
|
||||||
|
if (IsZero(frac32))
|
||||||
|
{
|
||||||
|
type = FPType.FPType_Infinity;
|
||||||
|
/* value = 2.0^1000000; */
|
||||||
|
value = MathF.Pow(2.0f, 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = frac32[22] ? FPType.FPType_QNaN : FPType.FPType_SNaN;
|
||||||
|
value = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.FPType_Nonzero;
|
||||||
|
value = MathF.Pow(2.0f, (int)UInt(exp32) - 127) * (1.0f + Real_32(UInt(frac32)) * MathF.Pow(2.0f, -23));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
{
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (type, sign, value);
|
||||||
|
}
|
||||||
|
public static (FPType, bool, double) FPUnpack_64(Bits fpval, Bits _fpcr)
|
||||||
|
{
|
||||||
|
int N = fpval.Count;
|
||||||
|
|
||||||
|
/* assert N == 64; */
|
||||||
|
|
||||||
|
Bits fpcr = new Bits(_fpcr); // Clone.
|
||||||
|
|
||||||
|
FPType type;
|
||||||
|
double value;
|
||||||
|
|
||||||
|
bool sign = fpval[63];
|
||||||
|
Bits exp64 = fpval[62, 52];
|
||||||
|
Bits frac64 = fpval[51, 0];
|
||||||
|
|
||||||
|
if (IsZero(exp64))
|
||||||
|
{
|
||||||
|
// Produce zero if value is zero or flush-to-zero is selected.
|
||||||
|
if (IsZero(frac64) || fpcr[24])
|
||||||
|
{
|
||||||
|
type = FPType.FPType_Zero;
|
||||||
|
value = 0.0;
|
||||||
|
|
||||||
|
// Denormalized input flushed to zero
|
||||||
|
if (!IsZero(frac64))
|
||||||
|
{
|
||||||
|
FPProcessException(FPExc.FPExc_InputDenorm, fpcr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.FPType_Nonzero;
|
||||||
|
value = Math.Pow(2.0, -1022) * (Real_64(UInt(frac64)) * Math.Pow(2.0, -52));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (IsOnes(exp64))
|
||||||
|
{
|
||||||
|
if (IsZero(frac64))
|
||||||
|
{
|
||||||
|
type = FPType.FPType_Infinity;
|
||||||
|
/* value = 2.0^1000000; */
|
||||||
|
value = Math.Pow(2.0, 10000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = frac64[51] ? FPType.FPType_QNaN : FPType.FPType_SNaN;
|
||||||
|
value = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = FPType.FPType_Nonzero;
|
||||||
|
value = Math.Pow(2.0, (int)UInt(exp64) - 1023) * (1.0 + Real_64(UInt(frac64)) * Math.Pow(2.0, -52));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
{
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (type, sign, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shared_pseudocode.html#impl-shared.FPUnpackCV.2 */
|
||||||
|
/* shared_pseudocode.html#impl-shared.FPUnpackBase.2 */
|
||||||
|
/*public static (FPType, bool, real) FPUnpackCV_16(Bits fpval, Bits _fpcr)
|
||||||
|
{
|
||||||
|
int N = fpval.Count;
|
||||||
|
|
||||||
|
// assert N == 16;
|
||||||
|
|
||||||
|
Bits fpcr = new Bits(_fpcr); // Clone.
|
||||||
|
|
||||||
|
fpcr[19] = false;
|
||||||
|
|
||||||
|
return FPUnpackBase_16(fpval, fpcr);
|
||||||
|
}*/
|
||||||
|
public static (FPType, bool, float) FPUnpackCV_32(Bits fpval, Bits _fpcr)
|
||||||
|
{
|
||||||
|
return FPUnpack_32(fpval, _fpcr);
|
||||||
|
}
|
||||||
|
public static (FPType, bool, double) FPUnpackCV_64(Bits fpval, Bits _fpcr)
|
||||||
|
{
|
||||||
|
return FPUnpack_64(fpval, _fpcr);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region "functions/integer/"
|
#region "functions/integer/"
|
||||||
/* shared_pseudocode.html#impl-shared.AddWithCarry.3 */
|
/* shared_pseudocode.html#impl-shared.AddWithCarry.3 */
|
||||||
public static (Bits, Bits) AddWithCarry(int N, Bits x, Bits y, bool carry_in)
|
public static (Bits, Bits) AddWithCarry(int N, Bits x, Bits y, bool carry_in)
|
||||||
|
@ -1117,7 +1570,12 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
public static Bits SP_EL0;
|
public static Bits SP_EL0;
|
||||||
public static Bits SP_EL1;
|
public static Bits SP_EL1;
|
||||||
|
|
||||||
|
public static Bits FPCR; // TODO: Add named fields.
|
||||||
|
// [ 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 22 | 21 20 | 19 | 18 17 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ]
|
||||||
|
// [ 0 | 0 | 0 | 0 | 0 | AHP | DN | FZ | RMode | Stride | FZ16 | Len | IDE | 0 | 0 | IXE | UFE | OFE | DZE | IOE | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 ]
|
||||||
public static Bits FPSR; // TODO: Add named fields.
|
public static Bits FPSR; // TODO: Add named fields.
|
||||||
|
// [ 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ]
|
||||||
|
// [ N | Z | C | V | QC | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | IDC | 0 | 0 | IXC | UFC | OFC | DZC | IOC ]
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "functions/system/"
|
#region "functions/system/"
|
||||||
|
@ -1178,6 +1636,8 @@ namespace Ryujinx.Tests.Cpu.Tester
|
||||||
/* shared_pseudocode.html#impl-shared.HaveEL.1 */
|
/* shared_pseudocode.html#impl-shared.HaveEL.1 */
|
||||||
public static bool HaveEL(Bits el)
|
public static bool HaveEL(Bits el)
|
||||||
{
|
{
|
||||||
|
// TODO: Implement ASL: "IN" as C#: "Bits.In()".
|
||||||
|
/* if el IN {EL1,EL0} then */
|
||||||
if (el == EL1 || el == EL0)
|
if (el == EL1 || el == EL0)
|
||||||
{
|
{
|
||||||
return true; // EL1 and EL0 must exist
|
return true; // EL1 and EL0 must exist
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
|
||||||
|
<TargetOS Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">windows</TargetOS>
|
||||||
|
<TargetOS Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">osx</TargetOS>
|
||||||
|
<TargetOS Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">linux</TargetOS>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@ -20,6 +24,13 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="CopyUnicorn" AfterTargets="Build">
|
||||||
|
<Copy SourceFiles="..\Ryujinx.Tests.Unicorn\libs\$(TargetOS)\unicorn.dll" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
|
||||||
|
<Copy SourceFiles="..\Ryujinx.Tests.Unicorn\libs\$(TargetOS)\libunicorn.dylib" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
|
||||||
|
<Copy SourceFiles="..\Ryujinx.Tests.Unicorn\libs\$(TargetOS)\libunicorn.so" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.HLE.Logging;
|
using Ryujinx.HLE.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
@ -7,6 +8,10 @@ namespace Ryujinx
|
||||||
{
|
{
|
||||||
static class ConsoleLog
|
static class ConsoleLog
|
||||||
{
|
{
|
||||||
|
private static Thread MessageThread;
|
||||||
|
|
||||||
|
private static BlockingCollection<LogEventArgs> MessageQueue;
|
||||||
|
|
||||||
private static Dictionary<LogLevel, ConsoleColor> LogColors;
|
private static Dictionary<LogLevel, ConsoleColor> LogColors;
|
||||||
|
|
||||||
private static object ConsoleLock;
|
private static object ConsoleLock;
|
||||||
|
@ -21,10 +26,34 @@ namespace Ryujinx
|
||||||
{ LogLevel.Error, ConsoleColor.Red }
|
{ LogLevel.Error, ConsoleColor.Red }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MessageQueue = new BlockingCollection<LogEventArgs>();
|
||||||
|
|
||||||
ConsoleLock = new object();
|
ConsoleLock = new object();
|
||||||
|
|
||||||
|
MessageThread = new Thread(() =>
|
||||||
|
{
|
||||||
|
while (!MessageQueue.IsCompleted)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PrintLog(MessageQueue.Take());
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
// IOE means that Take() was called on a completed collection.
|
||||||
|
// Some other thread can call CompleteAdding after we pass the
|
||||||
|
// IsCompleted check but before we call Take.
|
||||||
|
// We can simply catch the exception since the loop will break
|
||||||
|
// on the next iteration.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
MessageThread.IsBackground = true;
|
||||||
|
MessageThread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PrintLog(object sender, LogEventArgs e)
|
private static void PrintLog(LogEventArgs e)
|
||||||
{
|
{
|
||||||
string FormattedTime = e.Time.ToString(@"hh\:mm\:ss\.fff");
|
string FormattedTime = e.Time.ToString(@"hh\:mm\:ss\.fff");
|
||||||
|
|
||||||
|
@ -47,5 +76,13 @@ namespace Ryujinx
|
||||||
Console.WriteLine(Message);
|
Console.WriteLine(Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Log(object sender, LogEventArgs e)
|
||||||
|
{
|
||||||
|
if (!MessageQueue.IsAddingCompleted)
|
||||||
|
{
|
||||||
|
MessageQueue.Add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,7 +24,7 @@ namespace Ryujinx
|
||||||
|
|
||||||
Device.Hid.InitializeJoycons();
|
Device.Hid.InitializeJoycons();
|
||||||
|
|
||||||
Device.Log.Updated += ConsoleLog.PrintLog;
|
Device.Log.Updated += ConsoleLog.Log;
|
||||||
|
|
||||||
if (args.Length == 1)
|
if (args.Length == 1)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue