diff --git a/COMPILING.md b/COMPILING.md
index 238c1ade8..edfb35ac4 100644
--- a/COMPILING.md
+++ b/COMPILING.md
@@ -5,7 +5,7 @@ If you wish to build the emulator yourself, follow these steps:
### Step 1
-Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
+Install the [.NET 10.0 (or higher) SDK](https://dotnet.microsoft.com/en-us/download/dotnet/10.0).
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
### Step 2
diff --git a/Directory.Build.props b/Directory.Build.props
index d7a2ac1f2..a4df830a3 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,6 +1,6 @@
- net9.0
- latest
+ net10.0
+ preview
diff --git a/Ryujinx.sln b/Ryujinx.sln
index b25844245..24def42a3 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -85,6 +85,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.github\workflows\build.yml = .github\workflows\build.yml
.github\workflows\canary.yml = .github\workflows\canary.yml
Directory.Packages.props = Directory.Packages.props
+ Directory.Build.props = Directory.Build.props
.github\workflows\release.yml = .github\workflows\release.yml
nuget.config = nuget.config
EndProjectSection
diff --git a/global.json b/global.json
index cdbb589ed..512142d2b 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "9.0.100",
+ "version": "10.0.100",
"rollForward": "latestFeature"
}
}
diff --git a/src/ARMeilleure/CodeGen/Arm64/ArmCondition.cs b/src/ARMeilleure/CodeGen/Arm64/ArmCondition.cs
index 5db898591..755e9573a 100644
--- a/src/ARMeilleure/CodeGen/Arm64/ArmCondition.cs
+++ b/src/ARMeilleure/CodeGen/Arm64/ArmCondition.cs
@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.Arm64
static class ComparisonArm64Extensions
{
- public static ArmCondition ToArmCondition(this Comparison comp)
+ extension(Comparison comparison)
{
- return comp switch
+ public ArmCondition Arm => comparison switch
{
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => ArmCondition.Eq,
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.Arm64
Comparison.LessUI => ArmCondition.LtUn,
#pragma warning restore IDE0055
- _ => throw new ArgumentException(null, nameof(comp)),
+ _ => throw new ArgumentException(null, nameof(comparison))
};
}
}
diff --git a/src/ARMeilleure/CodeGen/Arm64/Assembler.cs b/src/ARMeilleure/CodeGen/Arm64/Assembler.cs
index 0d493426b..ee696c5f2 100644
--- a/src/ARMeilleure/CodeGen/Arm64/Assembler.cs
+++ b/src/ARMeilleure/CodeGen/Arm64/Assembler.cs
@@ -181,10 +181,10 @@ namespace ARMeilleure.CodeGen.Arm64
public void Fmov(Operand rd, Operand rn, bool topHalf)
{
- Debug.Assert(rd.Type.IsInteger() != rn.Type.IsInteger());
+ Debug.Assert(rd.Type.IsInteger != rn.Type.IsInteger);
Debug.Assert(rd.Type == OperandType.I64 || rn.Type == OperandType.I64 || !topHalf);
- uint opcode = rd.Type.IsInteger() ? 0b110u : 0b111u;
+ uint opcode = rd.Type.IsInteger ? 0b110u : 0b111u;
uint rmode = topHalf ? 1u << 19 : 0u;
uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 0u;
@@ -411,7 +411,7 @@ namespace ARMeilleure.CodeGen.Arm64
public void Mov(Operand rd, Operand rn)
{
- if (rd.Type.IsInteger())
+ if (rd.Type.IsInteger)
{
Orr(rd, Factory.Register(ZrRegister, RegisterType.Integer, rd.Type), rn);
}
@@ -973,7 +973,7 @@ namespace ARMeilleure.CodeGen.Arm64
uint instruction;
int scale;
- if (type.IsInteger())
+ if (type.IsInteger)
{
instruction = intInst;
@@ -1009,7 +1009,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
uint instruction;
- if (type.IsInteger())
+ if (type.IsInteger)
{
instruction = intInst;
diff --git a/src/ARMeilleure/CodeGen/Arm64/CodeGenerator.cs b/src/ARMeilleure/CodeGen/Arm64/CodeGenerator.cs
index fbf4c1eb4..320e86dc2 100644
--- a/src/ARMeilleure/CodeGen/Arm64/CodeGenerator.cs
+++ b/src/ARMeilleure/CodeGen/Arm64/CodeGenerator.cs
@@ -250,7 +250,7 @@ namespace ARMeilleure.CodeGen.Arm64
// ValidateBinOp(dest, src1, src2);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
context.Assembler.Add(dest, src1, src2);
}
@@ -268,7 +268,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.And(dest, src1, src2);
}
@@ -281,7 +281,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
context.Assembler.Eor(dest, src1, src2);
}
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Mvn(dest, source);
}
@@ -311,7 +311,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, src1, src2);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Orr(dest, src1, src2);
}
@@ -322,7 +322,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(comp.Kind == OperandKind.Constant);
- ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
+ ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
GenerateCompareCommon(context, operation);
@@ -336,7 +336,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Rev(dest, source);
}
@@ -354,7 +354,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type == OperandType.I32);
Debug.Assert(comp.Kind == OperandKind.Constant);
- ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
+ ArmCondition cond = ((Comparison)comp.AsInt32()).Arm;
GenerateCompareCommon(context, operation);
@@ -428,7 +428,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(src1, src2);
- Debug.Assert(src1.Type.IsInteger());
+ Debug.Assert(src1.Type.IsInteger);
context.Assembler.Cmp(src1, src2);
}
@@ -442,7 +442,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, src2, src3);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Cmp(src1, Const(src1.Type, 0));
@@ -468,7 +468,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type != source.Type);
Debug.Assert(source.Type != OperandType.V128);
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
context.Assembler.ScvtfScalar(dest, source);
}
@@ -485,7 +485,7 @@ namespace ARMeilleure.CodeGen.Arm64
Debug.Assert(dest.Type is OperandType.FP32 or OperandType.FP64);
Debug.Assert(dest.Type != source.Type);
- Debug.Assert(source.Type.IsInteger());
+ Debug.Assert(source.Type.IsInteger);
context.Assembler.UcvtfScalar(dest, source);
}
@@ -497,7 +497,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, source);
- Debug.Assert(dest.Type.IsInteger() || source.Kind != OperandKind.Constant);
+ Debug.Assert(dest.Type.IsInteger || source.Kind != OperandKind.Constant);
// Moves to the same register are useless.
if (dest.Kind == source.Kind && dest.Value == source.Value)
@@ -529,7 +529,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, source);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Clz(dest, source);
}
@@ -542,7 +542,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateBinOp(dest, dividend, divisor);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
context.Assembler.Sdiv(dest, dividend, divisor);
}
@@ -576,7 +576,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.Destination;
Operand address = operation.GetSource(0);
- Debug.Assert(value.Type.IsInteger());
+ Debug.Assert(value.Type.IsInteger);
context.Assembler.LdrhRiUn(value, address, 0);
}
@@ -586,7 +586,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.Destination;
Operand address = operation.GetSource(0);
- Debug.Assert(value.Type.IsInteger());
+ Debug.Assert(value.Type.IsInteger);
context.Assembler.LdrbRiUn(value, address, 0);
}
@@ -604,7 +604,7 @@ namespace ARMeilleure.CodeGen.Arm64
EnsureSameType(dest, src1, src2);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
context.Assembler.Mul(dest, src1, src2);
}
@@ -647,7 +647,7 @@ namespace ARMeilleure.CodeGen.Arm64
ValidateUnOp(dest, source);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
context.Assembler.Neg(dest, source);
}
@@ -732,7 +732,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxth(dest, source);
}
@@ -742,7 +742,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxtw(dest, source);
}
@@ -752,7 +752,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Sxtb(dest, source);
}
@@ -823,7 +823,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0);
- Debug.Assert(value.Type.IsInteger());
+ Debug.Assert(value.Type.IsInteger);
context.Assembler.StrhRiUn(value, address, 0);
}
@@ -833,7 +833,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand value = operation.GetSource(1);
Operand address = operation.GetSource(0);
- Debug.Assert(value.Type.IsInteger());
+ Debug.Assert(value.Type.IsInteger);
context.Assembler.StrbRiUn(value, address, 0);
}
@@ -858,7 +858,7 @@ namespace ARMeilleure.CodeGen.Arm64
// ValidateBinOp(dest, src1, src2);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
context.Assembler.Sub(dest, src1, src2);
}
@@ -882,7 +882,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (dest != default)
{
- Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(!dest.Type.IsInteger && source.Type.IsInteger);
OperandType destType = source.Type == OperandType.I64 ? OperandType.FP64 : OperandType.FP32;
@@ -901,9 +901,9 @@ namespace ARMeilleure.CodeGen.Arm64
byte index = src2.AsByte();
- Debug.Assert(index < OperandType.V128.GetSizeInBytes() / dest.Type.GetSizeInBytes());
+ Debug.Assert(index < OperandType.V128.ByteSize / dest.Type.ByteSize);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
context.Assembler.Umov(dest, src1, index, dest.Type == OperandType.I64 ? 3 : 2);
}
@@ -959,7 +959,7 @@ namespace ARMeilleure.CodeGen.Arm64
byte index = src3.AsByte();
- if (src2.Type.IsInteger())
+ if (src2.Type.IsInteger)
{
context.Assembler.Ins(dest, src2, index, src2.Type == OperandType.I64 ? 3 : 2);
}
@@ -1007,7 +1007,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand dest = operation.Destination;
- Debug.Assert(!dest.Type.IsInteger());
+ Debug.Assert(!dest.Type.IsInteger);
context.Assembler.CmeqVector(dest, dest, dest, 2);
}
@@ -1016,7 +1016,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand dest = operation.Destination;
- Debug.Assert(!dest.Type.IsInteger());
+ Debug.Assert(!dest.Type.IsInteger);
context.Assembler.EorVector(dest, dest, dest);
}
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Uxth(dest, source);
}
@@ -1056,7 +1056,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
// We can eliminate the move if source is already 32-bit and the registers are the same.
if (dest.Value == source.Value && source.Type == OperandType.I32)
@@ -1072,7 +1072,7 @@ namespace ARMeilleure.CodeGen.Arm64
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Uxtb(dest, source);
}
@@ -1169,7 +1169,7 @@ namespace ARMeilleure.CodeGen.Arm64
context.Assembler.StrRiPre(Register(reg, type), Register(SpRegister), -calleeSaveRegionSize);
}
- offset += type.GetSizeInBytes();
+ offset += type.ByteSize;
}
while (mask != 0)
@@ -1195,7 +1195,7 @@ namespace ARMeilleure.CodeGen.Arm64
context.Assembler.StpRiPre(Register(reg, type), Register(reg2, type), Register(SpRegister), -calleeSaveRegionSize);
}
- offset += type.GetSizeInBytes() * 2;
+ offset += type.ByteSize * 2;
}
}
@@ -1273,7 +1273,7 @@ namespace ARMeilleure.CodeGen.Arm64
mask &= ~(1 << reg2);
- offset -= type.GetSizeInBytes() * 2;
+ offset -= type.ByteSize * 2;
if (offset != 0)
{
@@ -1286,7 +1286,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
- offset -= type.GetSizeInBytes();
+ offset -= type.ByteSize;
if (offset != 0)
{
@@ -1435,12 +1435,12 @@ namespace ARMeilleure.CodeGen.Arm64
OperandType valueType = GetMemOpValueType(currentOp);
- if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.GetSizeInBytes() != op2Offset)
+ if (valueType != GetMemOpValueType(nextOp) || op1Offset + valueType.ByteSize != op2Offset)
{
return false;
}
- if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.GetSizeInBytesLog2()))
+ if (!CodeGenCommon.ConstFitsOnSImm7(op1Offset, valueType.ByteSizeLog2))
{
return false;
}
@@ -1549,7 +1549,7 @@ namespace ARMeilleure.CodeGen.Arm64
// EnsureSameReg (dest, src1);
EnsureSameType(dest, src1);
- Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
+ Debug.Assert(dest.Type.IsInteger && src2.Type == OperandType.I32);
}
private static void EnsureSameReg(Operand op1, Operand op2)
diff --git a/src/ARMeilleure/CodeGen/Arm64/CodeGeneratorIntrinsic.cs b/src/ARMeilleure/CodeGen/Arm64/CodeGeneratorIntrinsic.cs
index 390dc5b2e..e7871289b 100644
--- a/src/ARMeilleure/CodeGen/Arm64/CodeGeneratorIntrinsic.cs
+++ b/src/ARMeilleure/CodeGen/Arm64/CodeGeneratorIntrinsic.cs
@@ -462,7 +462,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
instruction |= (sz << 22);
- if (rd.Type.IsInteger())
+ if (rd.Type.IsInteger)
{
context.Assembler.WriteInstructionAuto(instruction, rd, rn);
}
@@ -490,7 +490,7 @@ namespace ARMeilleure.CodeGen.Arm64
instruction |= (sz << 22);
instruction |= (64 - fBits) << 10;
- if (rd.Type.IsInteger())
+ if (rd.Type.IsInteger)
{
Debug.Assert(rd.Type != OperandType.I32 || fBits <= 32);
diff --git a/src/ARMeilleure/CodeGen/Arm64/PreAllocator.cs b/src/ARMeilleure/CodeGen/Arm64/PreAllocator.cs
index 76a231d6c..d52aba162 100644
--- a/src/ARMeilleure/CodeGen/Arm64/PreAllocator.cs
+++ b/src/ARMeilleure/CodeGen/Arm64/PreAllocator.cs
@@ -112,7 +112,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src1.Kind == OperandKind.Constant)
{
- if (!src1.Type.IsInteger())
+ if (!src1.Type.IsInteger)
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src2.Kind == OperandKind.Constant)
{
- if (!src2.Type.IsInteger())
+ if (!src2.Type.IsInteger)
{
src2 = AddFloatConstantCopy(constants, nodes, node, src2);
@@ -191,7 +191,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (src.Kind == OperandKind.Constant)
{
- if (!src.Type.IsInteger())
+ if (!src.Type.IsInteger)
{
src = AddFloatConstantCopy(constants, nodes, node, src);
@@ -282,7 +282,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
passOnReg = intCount < intMax;
}
@@ -309,7 +309,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (passOnReg)
{
- Operand argReg = source.Type.IsInteger()
+ Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -327,7 +327,7 @@ namespace ARMeilleure.CodeGen.Arm64
InsertConstantRegCopies(constants, nodes, nodes.AddBefore(node, spillOp));
- stackOffset += source.Type.GetSizeInBytes();
+ stackOffset += source.Type.ByteSize;
}
}
@@ -345,7 +345,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
- Operand retReg = dest.Type.IsInteger()
+ Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
passOnReg = intCount + 1 < intMax;
}
@@ -408,7 +408,7 @@ namespace ARMeilleure.CodeGen.Arm64
if (passOnReg)
{
- Operand argReg = source.Type.IsInteger()
+ Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -521,7 +521,7 @@ namespace ARMeilleure.CodeGen.Arm64
}
else
{
- Operand retReg = source.Type.IsInteger()
+ Operand retReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
@@ -551,7 +551,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
OperandType argType = cctx.FuncArgTypes[cIndex];
- if (argType.IsInteger())
+ if (argType.IsInteger)
{
intCount++;
}
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.Arm64
bool passOnReg;
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
passOnReg = intCount < CallingConvention.GetArgumentsOnRegsCount();
}
@@ -606,7 +606,7 @@ namespace ARMeilleure.CodeGen.Arm64
{
Operand pArg = Local(dest.Type);
- Operand argReg = dest.Type.IsInteger()
+ Operand argReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
diff --git a/src/ARMeilleure/CodeGen/Optimizations/BlockPlacement.cs b/src/ARMeilleure/CodeGen/Optimizations/BlockPlacement.cs
index 5f0e37721..4a9f6a834 100644
--- a/src/ARMeilleure/CodeGen/Optimizations/BlockPlacement.cs
+++ b/src/ARMeilleure/CodeGen/Optimizations/BlockPlacement.cs
@@ -51,7 +51,7 @@ namespace ARMeilleure.CodeGen.Optimizations
if (trueSucc == block.ListNext)
{
Comparison comp = (Comparison)branchOp.GetSource(2).AsInt32();
- Comparison compInv = comp.Invert();
+ Comparison compInv = comp.Inverse;
branchOp.SetSource(2, Const((int)compInv));
diff --git a/src/ARMeilleure/CodeGen/Optimizations/Optimizer.cs b/src/ARMeilleure/CodeGen/Optimizations/Optimizer.cs
index cbc6ab784..c1de22757 100644
--- a/src/ARMeilleure/CodeGen/Optimizations/Optimizer.cs
+++ b/src/ARMeilleure/CodeGen/Optimizations/Optimizer.cs
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
}
else if (otherCompType == Comparison.Equal)
{
- propCompType = compType.Invert();
+ propCompType = compType.Inverse;
}
else
{
diff --git a/src/ARMeilleure/CodeGen/Optimizations/Simplification.cs b/src/ARMeilleure/CodeGen/Optimizations/Simplification.cs
index 53a7f3ede..a80b4adad 100644
--- a/src/ARMeilleure/CodeGen/Optimizations/Simplification.cs
+++ b/src/ARMeilleure/CodeGen/Optimizations/Simplification.cs
@@ -105,7 +105,7 @@ namespace ARMeilleure.CodeGen.Optimizations
Operand x = operation.GetSource(0);
Operand y = operation.GetSource(1);
- if (x == y && x.Type.IsInteger())
+ if (x == y && x.Type.IsInteger)
{
operation.TurnIntoCopy(Const(x.Type, 0));
}
@@ -161,7 +161,7 @@ namespace ARMeilleure.CodeGen.Optimizations
private static bool IsConstEqual(Operand operand, ulong comparand)
{
- if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger())
+ if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger)
{
return false;
}
diff --git a/src/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs b/src/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs
index 8b135afab..574de4cd6 100644
--- a/src/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs
+++ b/src/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs
@@ -98,7 +98,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
OperandType type = types[copyDest];
- type = type.IsInteger() ? OperandType.I64 : OperandType.V128;
+ type = type.IsInteger ? OperandType.I64 : OperandType.V128;
EmitXorSwap(sequence, GetRegister(copyDest, type), GetRegister(copySource, type));
diff --git a/src/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs b/src/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs
index 5f1d6ce89..1e9aee5fd 100644
--- a/src/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs
+++ b/src/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs
@@ -178,7 +178,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
else if (dest.Kind == OperandKind.Register)
{
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
intFixedRegisters |= 1 << dest.GetRegister().Index;
}
@@ -236,7 +236,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
Register reg = info.Register.GetRegister();
- if (local.Type.IsInteger())
+ if (local.Type.IsInteger)
{
intLocalFreeRegisters |= 1 << reg.Index;
}
@@ -254,7 +254,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (temp == default || info.Sequence != sequence)
{
- temp = local.Type.IsInteger()
+ temp = local.Type.IsInteger
? GetSpillTemp(local, intSpillTempRegisters, ref intLocalUse)
: GetSpillTemp(local, vecSpillTempRegisters, ref vecLocalUse);
@@ -335,7 +335,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (info.UsesAllocated == 0)
{
- int mask = dest.Type.IsInteger()
+ int mask = dest.Type.IsInteger
? intLocalFreeRegisters
: vecLocalFreeRegisters;
@@ -343,9 +343,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
int selectedReg = BitOperations.TrailingZeroCount(mask);
- info.Register = Register(selectedReg, info.Type.ToRegisterType(), info.Type);
+ info.Register = Register(selectedReg, info.Type.Register, info.Type);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
intLocalFreeRegisters &= ~(1 << selectedReg);
intUsedRegisters |= 1 << selectedReg;
@@ -359,7 +359,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
else
{
info.Register = default;
- info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes()));
+ info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.ByteSize));
}
}
@@ -377,7 +377,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (temp == default || info.Sequence != sequence)
{
- temp = dest.Type.IsInteger()
+ temp = dest.Type.IsInteger
? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
: GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
@@ -443,7 +443,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
useMask |= 1 << selectedReg;
- return Register(selectedReg, local.Type.ToRegisterType(), local.Type);
+ return Register(selectedReg, local.Type.Register, local.Type);
}
private static int UsesCount(Operand local)
diff --git a/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs b/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs
index 92fedf7bf..94883b39b 100644
--- a/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs
+++ b/src/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs
@@ -208,7 +208,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private bool TryAllocateRegWithoutSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
{
- RegisterType regType = current.Local.Type.ToRegisterType();
+ RegisterType regType = current.Local.Type.Register;
Span freePositions = stackalloc int[registersCount];
@@ -318,7 +318,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private void AllocateRegWithSpill(AllocationContext context, LiveInterval current, int cIndex, int registersCount)
{
- RegisterType regType = current.Local.Type.ToRegisterType();
+ RegisterType regType = current.Local.Type.Register;
Span usePositions = stackalloc int[registersCount];
Span blockedPositions = stackalloc int[registersCount];
diff --git a/src/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs b/src/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs
index 13995bc8d..b89034609 100644
--- a/src/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs
+++ b/src/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs
@@ -10,7 +10,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public int Allocate(OperandType type)
{
- return Allocate(type.GetSizeInBytes());
+ return Allocate(type.ByteSize);
}
public int Allocate(int sizeInBytes)
diff --git a/src/ARMeilleure/CodeGen/X86/Assembler.cs b/src/ARMeilleure/CodeGen/X86/Assembler.cs
index 5a8312806..e12866990 100644
--- a/src/ARMeilleure/CodeGen/X86/Assembler.cs
+++ b/src/ARMeilleure/CodeGen/X86/Assembler.cs
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
{
ref readonly InstructionInfo info = ref _instTable[(int)X86Instruction.Movd];
- if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
+ if (source.Type.IsInteger || source.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, info.Flags, info.OpRRM, rrm: true);
}
@@ -416,11 +416,11 @@ namespace ARMeilleure.CodeGen.X86
InstructionFlags flags = info.Flags | InstructionFlags.RexW;
- if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
+ if (source.Type.IsInteger || source.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRRM, rrm: true);
}
- else if (dest.Type.IsInteger() || dest.Kind == OperandKind.Memory)
+ else if (dest.Type.IsInteger || dest.Kind == OperandKind.Memory)
{
WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRMR);
}
diff --git a/src/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/src/ARMeilleure/CodeGen/X86/CodeGenerator.cs
index 86acea4a8..ed425f476 100644
--- a/src/ARMeilleure/CodeGen/X86/CodeGenerator.cs
+++ b/src/ARMeilleure/CodeGen/X86/CodeGenerator.cs
@@ -289,7 +289,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Popcnt(dest, source, dest.Type);
@@ -303,7 +303,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
- Debug.Assert(!dest.Type.IsInteger());
+ Debug.Assert(!dest.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, source);
@@ -315,7 +315,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && !source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && !source.Type.IsInteger);
if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
{
@@ -349,8 +349,8 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
- Debug.Assert(!dest.Type.IsInteger());
- Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
+ Debug.Assert(!dest.Type.IsInteger);
+ Debug.Assert(!src2.Type.IsInteger || src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
@@ -370,7 +370,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
- Debug.Assert(!dest.Type.IsInteger() && src2.Type.IsInteger());
+ Debug.Assert(!dest.Type.IsInteger && src2.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
@@ -385,7 +385,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
- Debug.Assert(dest.Type.IsInteger() && src1.Type.IsInteger() && src2.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && src1.Type.IsInteger && src2.Type.IsInteger);
context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type);
@@ -405,7 +405,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
- Debug.Assert(!dest.Type.IsInteger() && src2.Kind == OperandKind.Constant);
+ Debug.Assert(!dest.Type.IsInteger && src2.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2.AsByte());
@@ -421,7 +421,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, src1, src2, src3);
- Debug.Assert(!dest.Type.IsInteger());
+ Debug.Assert(!dest.Type.IsInteger);
if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
{
@@ -461,7 +461,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
}
- Debug.Assert(!dest.Type.IsInteger() && src3.Kind == OperandKind.Constant);
+ Debug.Assert(!dest.Type.IsInteger && src3.Kind == OperandKind.Constant);
context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte());
@@ -512,7 +512,7 @@ namespace ARMeilleure.CodeGen.X86
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
// If Destination and Source 1 Operands are the same, perform a standard add as there are no benefits to using LEA.
if (dest.Kind == src1.Kind && dest.Value == src1.Value)
@@ -567,7 +567,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
// Note: GenerateCompareCommon makes the assumption that BitwiseAnd will emit only a single `and`
// instruction.
@@ -582,7 +582,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
context.Assembler.Xor(dest, src2, dest.Type);
}
@@ -599,7 +599,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Not(dest);
}
@@ -612,7 +612,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Or(dest, src2, dest.Type);
}
@@ -623,7 +623,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(comp.Kind == OperandKind.Constant);
- X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
+ X86Condition cond = ((Comparison)comp.AsInt32()).X86;
GenerateCompareCommon(context, operation);
@@ -637,7 +637,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Bswap(dest);
}
@@ -661,7 +661,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(dest.Type == OperandType.I32);
Debug.Assert(comp.Kind == OperandKind.Constant);
- X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
+ X86Condition cond = ((Comparison)comp.AsInt32()).X86;
GenerateCompareCommon(context, operation);
@@ -676,7 +676,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(src1, src2);
- Debug.Assert(src1.Type.IsInteger());
+ Debug.Assert(src1.Type.IsInteger);
if (src2.Kind == OperandKind.Constant && src2.Value == 0)
{
@@ -766,7 +766,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src3);
EnsureSameType(dest, src2, src3);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
Debug.Assert(src1.Type == OperandType.I32);
context.Assembler.Test(src1, src1, src1.Type);
@@ -792,9 +792,9 @@ namespace ARMeilleure.CodeGen.X86
if (dest.Type == OperandType.FP32)
{
- Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP64);
+ Debug.Assert(source.Type.IsInteger || source.Type == OperandType.FP64);
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
@@ -808,9 +808,9 @@ namespace ARMeilleure.CodeGen.X86
}
else /* if (dest.Type == OperandType.FP64) */
{
- Debug.Assert(source.Type.IsInteger() || source.Type == OperandType.FP32);
+ Debug.Assert(source.Type.IsInteger || source.Type == OperandType.FP32);
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
context.Assembler.Xorps(dest, dest, dest);
context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
@@ -831,7 +831,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
- Debug.Assert(dest.Type.IsInteger() || source.Kind != OperandKind.Constant);
+ Debug.Assert(dest.Type.IsInteger || source.Kind != OperandKind.Constant);
// Moves to the same register are useless.
if (dest.Kind == source.Kind && dest.Value == source.Value)
@@ -845,7 +845,7 @@ namespace ARMeilleure.CodeGen.X86
// Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient.
context.Assembler.Xor(dest, dest, OperandType.I32);
}
- else if (dest.Type.IsInteger())
+ else if (dest.Type.IsInteger)
{
context.Assembler.Mov(dest, source, dest.Type);
}
@@ -862,7 +862,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, source);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Bsr(dest, source, dest.Type);
@@ -894,12 +894,12 @@ namespace ARMeilleure.CodeGen.X86
Operand dividend = operation.GetSource(0);
Operand divisor = operation.GetSource(1);
- if (!dest.Type.IsInteger())
+ if (!dest.Type.IsInteger)
{
ValidateBinOp(dest, dividend, divisor);
}
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
divisor = operation.GetSource(2);
@@ -932,7 +932,7 @@ namespace ARMeilleure.CodeGen.X86
Operand rdx = Register(X86Register.Rdx);
- Debug.Assert(divisor.Type.IsInteger());
+ Debug.Assert(divisor.Type.IsInteger);
context.Assembler.Xor(rdx, rdx, OperandType.I32);
context.Assembler.Div(divisor);
@@ -967,7 +967,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
- Debug.Assert(value.Type.IsInteger());
+ Debug.Assert(value.Type.IsInteger);
context.Assembler.Movzx16(value, address, value.Type);
}
@@ -977,7 +977,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.Destination;
Operand address = Memory(operation.GetSource(0), value.Type);
- Debug.Assert(value.Type.IsInteger());
+ Debug.Assert(value.Type.IsInteger);
context.Assembler.Movzx8(value, address, value.Type);
}
@@ -1000,7 +1000,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(dest, src1, src2);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
if (src2.Kind == OperandKind.Constant)
{
@@ -1046,7 +1046,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateUnOp(dest, source);
- Debug.Assert(dest.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger);
context.Assembler.Neg(dest);
}
@@ -1107,7 +1107,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx16(dest, source, dest.Type);
}
@@ -1117,7 +1117,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx32(dest, source, dest.Type);
}
@@ -1127,7 +1127,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movsx8(dest, source, dest.Type);
}
@@ -1187,7 +1187,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
- Debug.Assert(value.Type.IsInteger());
+ Debug.Assert(value.Type.IsInteger);
context.Assembler.Mov16(address, value);
}
@@ -1197,7 +1197,7 @@ namespace ARMeilleure.CodeGen.X86
Operand value = operation.GetSource(1);
Operand address = Memory(operation.GetSource(0), value.Type);
- Debug.Assert(value.Type.IsInteger());
+ Debug.Assert(value.Type.IsInteger);
context.Assembler.Mov8(address, value);
}
@@ -1210,7 +1210,7 @@ namespace ARMeilleure.CodeGen.X86
ValidateBinOp(dest, src1, src2);
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
context.Assembler.Sub(dest, src2, dest.Type);
}
@@ -1236,7 +1236,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(!dest.Type.IsInteger && source.Type.IsInteger);
if (source.Type == OperandType.I32)
{
@@ -1259,7 +1259,7 @@ namespace ARMeilleure.CodeGen.X86
byte index = src2.AsByte();
- Debug.Assert(index < OperandType.V128.GetSizeInBytes() / dest.Type.GetSizeInBytes());
+ Debug.Assert(index < OperandType.V128.ByteSize / dest.Type.ByteSize);
if (dest.Type == OperandType.I32)
{
@@ -1541,7 +1541,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand dest = operation.Destination;
- Debug.Assert(!dest.Type.IsInteger());
+ Debug.Assert(!dest.Type.IsInteger);
context.Assembler.Pcmpeqw(dest, dest, dest);
}
@@ -1550,7 +1550,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand dest = operation.Destination;
- Debug.Assert(!dest.Type.IsInteger());
+ Debug.Assert(!dest.Type.IsInteger);
context.Assembler.Xorps(dest, dest, dest);
}
@@ -1580,7 +1580,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movzx16(dest, source, OperandType.I32);
}
@@ -1590,7 +1590,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
// We can eliminate the move if source is already 32-bit and the registers are the same.
if (dest.Value == source.Value && source.Type == OperandType.I32)
@@ -1606,7 +1606,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = operation.Destination;
Operand source = operation.GetSource(0);
- Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
+ Debug.Assert(dest.Type.IsInteger && source.Type.IsInteger);
context.Assembler.Movzx8(dest, source, OperandType.I32);
}
@@ -1713,12 +1713,12 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameReg(dest, src1);
EnsureSameType(dest, src1);
- Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
+ Debug.Assert(dest.Type.IsInteger && src2.Type == OperandType.I32);
}
private static void EnsureSameReg(Operand op1, Operand op2)
{
- if (!op1.Type.IsInteger() && HardwareCapabilities.SupportsVexEncoding)
+ if (!op1.Type.IsInteger && HardwareCapabilities.SupportsVexEncoding)
{
return;
}
diff --git a/src/ARMeilleure/CodeGen/X86/PreAllocator.cs b/src/ARMeilleure/CodeGen/X86/PreAllocator.cs
index 6b93efdfb..d3bc6be6a 100644
--- a/src/ARMeilleure/CodeGen/X86/PreAllocator.cs
+++ b/src/ARMeilleure/CodeGen/X86/PreAllocator.cs
@@ -86,7 +86,7 @@ namespace ARMeilleure.CodeGen.X86
break;
case Instruction.Negate:
- if (!node.GetSource(0).Type.IsInteger())
+ if (!node.GetSource(0).Type.IsInteger)
{
GenerateNegate(block.Operations, node);
}
@@ -159,7 +159,7 @@ namespace ARMeilleure.CodeGen.X86
if (src1.Kind == OperandKind.Constant)
{
- if (!src1.Type.IsInteger())
+ if (!src1.Type.IsInteger)
{
// Handle non-integer types (FP32, FP64 and V128).
// For instructions without an immediate operand, we do the following:
@@ -208,7 +208,7 @@ namespace ARMeilleure.CodeGen.X86
if (src2.Kind == OperandKind.Constant)
{
- if (!src2.Type.IsInteger())
+ if (!src2.Type.IsInteger)
{
src2 = AddXmmCopy(nodes, node, src2);
@@ -298,7 +298,7 @@ namespace ARMeilleure.CodeGen.X86
// - The dividend is always in RDX:RAX.
// - The result is always in RAX.
// - Additionally it also writes the remainder in RDX.
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
Operand src1 = node.GetSource(0);
@@ -466,7 +466,7 @@ namespace ARMeilleure.CodeGen.X86
Operand dest = node.Destination;
Operand source = node.GetSource(0);
- Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
+ Debug.Assert(source.Type.IsInteger, $"Invalid source type \"{source.Type}\".");
Operation currentNode = node;
@@ -654,10 +654,10 @@ namespace ARMeilleure.CodeGen.X86
switch (operation.Instruction)
{
case Instruction.Add:
- return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
+ return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
case Instruction.Multiply:
case Instruction.Subtract:
- return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger();
+ return !HardwareCapabilities.SupportsVexEncoding || operation.Destination.Type.IsInteger;
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
@@ -672,7 +672,7 @@ namespace ARMeilleure.CodeGen.X86
return true;
case Instruction.Divide:
- return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger();
+ return !HardwareCapabilities.SupportsVexEncoding && !operation.Destination.Type.IsInteger;
case Instruction.VectorInsert:
case Instruction.VectorInsert16:
diff --git a/src/ARMeilleure/CodeGen/X86/PreAllocatorSystemV.cs b/src/ARMeilleure/CodeGen/X86/PreAllocatorSystemV.cs
index cff1c7240..368c53789 100644
--- a/src/ARMeilleure/CodeGen/X86/PreAllocatorSystemV.cs
+++ b/src/ARMeilleure/CodeGen/X86/PreAllocatorSystemV.cs
@@ -35,7 +35,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
passOnReg = intCount < intMax;
}
@@ -62,7 +62,7 @@ namespace ARMeilleure.CodeGen.X86
if (passOnReg)
{
- Operand argReg = source.Type.IsInteger()
+ Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -80,7 +80,7 @@ namespace ARMeilleure.CodeGen.X86
InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
- stackOffset += source.Type.GetSizeInBytes();
+ stackOffset += source.Type.ByteSize;
}
}
@@ -102,7 +102,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
- Operand retReg = dest.Type.IsInteger()
+ Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -137,7 +137,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
passOnReg = intCount + 1 < intMax;
}
@@ -160,7 +160,7 @@ namespace ARMeilleure.CodeGen.X86
if (passOnReg)
{
- Operand argReg = source.Type.IsInteger()
+ Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
@@ -210,7 +210,7 @@ namespace ARMeilleure.CodeGen.X86
{
OperandType argType = cctx.FuncArgTypes[cIndex];
- if (argType.IsInteger())
+ if (argType.IsInteger)
{
intCount++;
}
@@ -226,7 +226,7 @@ namespace ARMeilleure.CodeGen.X86
bool passOnReg;
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
}
@@ -265,7 +265,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand pArg = Local(dest.Type);
- Operand argReg = dest.Type.IsInteger()
+ Operand argReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
@@ -320,7 +320,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
- Operand retReg = source.Type.IsInteger()
+ Operand retReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
diff --git a/src/ARMeilleure/CodeGen/X86/PreAllocatorWindows.cs b/src/ARMeilleure/CodeGen/X86/PreAllocatorWindows.cs
index 52f72ac69..6f4458d74 100644
--- a/src/ARMeilleure/CodeGen/X86/PreAllocatorWindows.cs
+++ b/src/ARMeilleure/CodeGen/X86/PreAllocatorWindows.cs
@@ -40,7 +40,7 @@ namespace ARMeilleure.CodeGen.X86
if (dest != default && dest.Type == OperandType.V128)
{
- int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
+ int stackOffset = AllocateOnStack(dest.Type.ByteSize);
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
@@ -76,7 +76,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand stackAddr = Local(OperandType.I64);
- int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());
+ int stackOffset = AllocateOnStack(source.Type.ByteSize);
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
@@ -96,7 +96,7 @@ namespace ARMeilleure.CodeGen.X86
int argIndex = index + retArgs;
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(argIndex), source.Type);
}
@@ -140,7 +140,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
- Operand retReg = dest.Type.IsInteger()
+ Operand retReg = dest.Type.IsInteger
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
@@ -171,7 +171,7 @@ namespace ARMeilleure.CodeGen.X86
for (int index = 0; index < argsCount; index++)
{
Operand source = node.GetSource(1 + index);
- Operand argReg = source.Type.IsInteger()
+ Operand argReg = source.Type.IsInteger
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
@@ -219,7 +219,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand argReg, pArg;
- if (dest.Type.IsInteger())
+ if (dest.Type.IsInteger)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
pArg = Local(dest.Type);
@@ -283,7 +283,7 @@ namespace ARMeilleure.CodeGen.X86
Operand source = node.GetSource(0);
Operand retReg;
- if (source.Type.IsInteger())
+ if (source.Type.IsInteger)
{
retReg = Gpr(CallingConvention.GetIntReturnRegister(), source.Type);
}
diff --git a/src/ARMeilleure/CodeGen/X86/X86Condition.cs b/src/ARMeilleure/CodeGen/X86/X86Condition.cs
index 70699a207..5153599b1 100644
--- a/src/ARMeilleure/CodeGen/X86/X86Condition.cs
+++ b/src/ARMeilleure/CodeGen/X86/X86Condition.cs
@@ -25,9 +25,9 @@ namespace ARMeilleure.CodeGen.X86
static class ComparisonX86Extensions
{
- public static X86Condition ToX86Condition(this Comparison comp)
+ extension(Comparison comparison)
{
- return comp switch
+ public X86Condition X86 => comparison switch
{
#pragma warning disable IDE0055 // Disable formatting
Comparison.Equal => X86Condition.Equal,
@@ -42,7 +42,7 @@ namespace ARMeilleure.CodeGen.X86
Comparison.LessUI => X86Condition.Below,
#pragma warning restore IDE0055
- _ => throw new ArgumentException(null, nameof(comp)),
+ _ => throw new ArgumentException(null, nameof(comparison))
};
}
}
diff --git a/src/ARMeilleure/Decoders/Condition.cs b/src/ARMeilleure/Decoders/Condition.cs
index 961825a10..bffe61ad5 100644
--- a/src/ARMeilleure/Decoders/Condition.cs
+++ b/src/ARMeilleure/Decoders/Condition.cs
@@ -22,11 +22,11 @@ namespace ARMeilleure.Decoders
static class ConditionExtensions
{
- public static Condition Invert(this Condition cond)
+ extension(Condition condition)
{
// Bit 0 of all conditions is basically a negation bit, so
// inverting this bit has the effect of inverting the condition.
- return (Condition)((int)cond ^ 1);
+ public Condition Inverse => (Condition)((int)condition ^ 1);
}
}
}
diff --git a/src/ARMeilleure/Instructions/InstEmitHashHelper.cs b/src/ARMeilleure/Instructions/InstEmitHashHelper.cs
index 19a607dfc..92f9c9c35 100644
--- a/src/ARMeilleure/Instructions/InstEmitHashHelper.cs
+++ b/src/ARMeilleure/Instructions/InstEmitHashHelper.cs
@@ -16,7 +16,7 @@ namespace ARMeilleure.Instructions
public static Operand EmitCrc32(ArmEmitterContext context, Operand crc, Operand value, int size, bool castagnoli)
{
- Debug.Assert(crc.Type.IsInteger() && value.Type.IsInteger());
+ Debug.Assert(crc.Type.IsInteger && value.Type.IsInteger);
Debug.Assert(size is >= 0 and < 4);
Debug.Assert((size < 3) || (value.Type == OperandType.I64));
diff --git a/src/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/src/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
index bb7e997b2..3874d0464 100644
--- a/src/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
+++ b/src/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
@@ -157,7 +157,7 @@ namespace ARMeilleure.Instructions
context.Copy(temp, value);
- if (!context.Memory.Type.IsHostMappedOrTracked())
+ if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -198,7 +198,7 @@ namespace ARMeilleure.Instructions
SetInt(context, rt, value);
- if (!context.Memory.Type.IsHostMappedOrTracked())
+ if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -265,7 +265,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(rt), value);
- if (!context.Memory.Type.IsHostMappedOrTracked())
+ if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -312,7 +312,7 @@ namespace ARMeilleure.Instructions
break;
}
- if (!context.Memory.Type.IsHostMappedOrTracked())
+ if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -385,7 +385,7 @@ namespace ARMeilleure.Instructions
break;
}
- if (!context.Memory.Type.IsHostMappedOrTracked())
+ if (!context.Memory.Type.IsHostMappedOrTracked)
{
context.Branch(lblEnd);
@@ -399,11 +399,11 @@ namespace ARMeilleure.Instructions
public static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath, bool write, int size)
{
- if (context.Memory.Type.IsHostMapped())
+ if (context.Memory.Type.IsHostMapped)
{
return EmitHostMappedPointer(context, address);
}
- else if (context.Memory.Type.IsHostTracked())
+ else if (context.Memory.Type.IsHostTracked)
{
if (address.Type == OperandType.I32)
{
diff --git a/src/ARMeilleure/Instructions/SoftFallback.cs b/src/ARMeilleure/Instructions/SoftFallback.cs
deleted file mode 100644
index c227156e5..000000000
--- a/src/ARMeilleure/Instructions/SoftFallback.cs
+++ /dev/null
@@ -1,692 +0,0 @@
-using ARMeilleure.State;
-using System;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Instructions
-{
- static class SoftFallback
- {
- #region "ShrImm64"
- [UnmanagedCallersOnly]
- public static long SignedShrImm64(long value, long roundConst, int shift)
- {
- if (roundConst == 0L)
- {
- if (shift <= 63)
- {
- return value >> shift;
- }
- else /* if (shift == 64) */
- {
- if (value < 0L)
- {
- return -1L;
- }
- else /* if (value >= 0L) */
- {
- return 0L;
- }
- }
- }
- else /* if (roundConst == 1L << (shift - 1)) */
- {
- if (shift <= 63)
- {
- long add = value + roundConst;
-
- if ((~value & (value ^ add)) < 0L)
- {
- return (long)((ulong)add >> shift);
- }
- else
- {
- return add >> shift;
- }
- }
- else /* if (shift == 64) */
- {
- return 0L;
- }
- }
- }
-
- [UnmanagedCallersOnly]
- public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
- {
- if (roundConst == 0L)
- {
- if (shift <= 63)
- {
- return value >> shift;
- }
- else /* if (shift == 64) */
- {
- return 0UL;
- }
- }
- else /* if (roundConst == 1L << (shift - 1)) */
- {
- ulong add = value + (ulong)roundConst;
-
- if ((add < value) && (add < (ulong)roundConst))
- {
- if (shift <= 63)
- {
- return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
- }
- else /* if (shift == 64) */
- {
- return 1UL;
- }
- }
- else
- {
- if (shift <= 63)
- {
- return add >> shift;
- }
- else /* if (shift == 64) */
- {
- return 0UL;
- }
- }
- }
- }
- #endregion
-
- #region "Saturation"
- [UnmanagedCallersOnly]
- public static int SatF32ToS32(float value)
- {
- if (float.IsNaN(value))
- {
- return 0;
- }
-
- return value >= int.MaxValue ? int.MaxValue :
- value <= int.MinValue ? int.MinValue : (int)value;
- }
-
- [UnmanagedCallersOnly]
- public static long SatF32ToS64(float value)
- {
- if (float.IsNaN(value))
- {
- return 0;
- }
-
- return value >= long.MaxValue ? long.MaxValue :
- value <= long.MinValue ? long.MinValue : (long)value;
- }
-
- [UnmanagedCallersOnly]
- public static uint SatF32ToU32(float value)
- {
- if (float.IsNaN(value))
- {
- return 0;
- }
-
- return value >= uint.MaxValue ? uint.MaxValue :
- value <= uint.MinValue ? uint.MinValue : (uint)value;
- }
-
- [UnmanagedCallersOnly]
- public static ulong SatF32ToU64(float value)
- {
- if (float.IsNaN(value))
- {
- return 0;
- }
-
- return value >= ulong.MaxValue ? ulong.MaxValue :
- value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
- }
-
- [UnmanagedCallersOnly]
- public static int SatF64ToS32(double value)
- {
- if (double.IsNaN(value))
- {
- return 0;
- }
-
- return value >= int.MaxValue ? int.MaxValue :
- value <= int.MinValue ? int.MinValue : (int)value;
- }
-
- [UnmanagedCallersOnly]
- public static long SatF64ToS64(double value)
- {
- if (double.IsNaN(value))
- {
- return 0;
- }
-
- return value >= long.MaxValue ? long.MaxValue :
- value <= long.MinValue ? long.MinValue : (long)value;
- }
-
- [UnmanagedCallersOnly]
- public static uint SatF64ToU32(double value)
- {
- if (double.IsNaN(value))
- {
- return 0;
- }
-
- return value >= uint.MaxValue ? uint.MaxValue :
- value <= uint.MinValue ? uint.MinValue : (uint)value;
- }
-
- [UnmanagedCallersOnly]
- public static ulong SatF64ToU64(double value)
- {
- if (double.IsNaN(value))
- {
- return 0;
- }
-
- return value >= ulong.MaxValue ? ulong.MaxValue :
- value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
- }
- #endregion
-
- #region "Count"
- [UnmanagedCallersOnly]
- public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
- {
- value ^= value >> 1;
-
- int highBit = size - 2;
-
- for (int bit = highBit; bit >= 0; bit--)
- {
- if (((int)(value >> bit) & 0b1) != 0)
- {
- return (ulong)(highBit - bit);
- }
- }
-
- return (ulong)(size - 1);
- }
-
- private static ReadOnlySpan ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
-
- [UnmanagedCallersOnly]
- public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
- {
- if (value == 0ul)
- {
- return (ulong)size;
- }
-
- int nibbleIdx = size;
- int preCount, count = 0;
-
- do
- {
- nibbleIdx -= 4;
- preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111];
- count += preCount;
- }
- while (preCount == 4);
-
- return (ulong)count;
- }
- #endregion
-
- #region "Table"
- [UnmanagedCallersOnly]
- public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
- {
- return TblOrTbx(default, vector, bytes, tb0);
- }
-
- [UnmanagedCallersOnly]
- public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
- {
- return TblOrTbx(default, vector, bytes, tb0, tb1);
- }
-
- [UnmanagedCallersOnly]
- public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
- {
- return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
- }
-
- [UnmanagedCallersOnly]
- public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
- {
- return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
- }
-
- [UnmanagedCallersOnly]
- public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
- {
- return TblOrTbx(dest, vector, bytes, tb0);
- }
-
- [UnmanagedCallersOnly]
- public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
- {
- return TblOrTbx(dest, vector, bytes, tb0, tb1);
- }
-
- [UnmanagedCallersOnly]
- public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
- {
- return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
- }
-
- [UnmanagedCallersOnly]
- public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
- {
- return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
- }
-
- private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params ReadOnlySpan tb)
- {
- byte[] res = new byte[16];
-
- if (dest != default)
- {
- Buffer.BlockCopy(dest.ToArray(), 0, res, 0, bytes);
- }
-
- byte[] table = new byte[tb.Length * 16];
-
- for (byte index = 0; index < tb.Length; index++)
- {
- Buffer.BlockCopy(tb[index].ToArray(), 0, table, index * 16, 16);
- }
-
- byte[] v = vector.ToArray();
-
- for (byte index = 0; index < bytes; index++)
- {
- byte tblIndex = v[index];
-
- if (tblIndex < table.Length)
- {
- res[index] = table[tblIndex];
- }
- }
-
- return new V128(res);
- }
- #endregion
-
- #region "Crc32"
- private const uint Crc32RevPoly = 0xedb88320;
- private const uint Crc32cRevPoly = 0x82f63b78;
-
- [UnmanagedCallersOnly]
- public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
- [UnmanagedCallersOnly]
- public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
- [UnmanagedCallersOnly]
- public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
- [UnmanagedCallersOnly]
- public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
-
- [UnmanagedCallersOnly]
- public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
- [UnmanagedCallersOnly]
- public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
- [UnmanagedCallersOnly]
- public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
- [UnmanagedCallersOnly]
- public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
-
- private static uint Crc32h(uint crc, uint poly, ushort val)
- {
- crc = Crc32(crc, poly, (byte)(val >> 0));
- crc = Crc32(crc, poly, (byte)(val >> 8));
-
- return crc;
- }
-
- private static uint Crc32w(uint crc, uint poly, uint val)
- {
- crc = Crc32(crc, poly, (byte)(val >> 0));
- crc = Crc32(crc, poly, (byte)(val >> 8));
- crc = Crc32(crc, poly, (byte)(val >> 16));
- crc = Crc32(crc, poly, (byte)(val >> 24));
-
- return crc;
- }
-
- private static uint Crc32x(uint crc, uint poly, ulong val)
- {
- crc = Crc32(crc, poly, (byte)(val >> 0));
- crc = Crc32(crc, poly, (byte)(val >> 8));
- crc = Crc32(crc, poly, (byte)(val >> 16));
- crc = Crc32(crc, poly, (byte)(val >> 24));
- crc = Crc32(crc, poly, (byte)(val >> 32));
- crc = Crc32(crc, poly, (byte)(val >> 40));
- crc = Crc32(crc, poly, (byte)(val >> 48));
- crc = Crc32(crc, poly, (byte)(val >> 56));
-
- return crc;
- }
-
- private static uint Crc32(uint crc, uint poly, byte val)
- {
- crc ^= val;
-
- for (int bit = 7; bit >= 0; bit--)
- {
- uint mask = (uint)(-(int)(crc & 1));
-
- crc = (crc >> 1) ^ (poly & mask);
- }
-
- return crc;
- }
- #endregion
-
- #region "Aes"
- [UnmanagedCallersOnly]
- public static V128 Decrypt(V128 value, V128 roundKey)
- {
- return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
- }
-
- [UnmanagedCallersOnly]
- public static V128 Encrypt(V128 value, V128 roundKey)
- {
- return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
- }
-
- [UnmanagedCallersOnly]
- public static V128 InverseMixColumns(V128 value)
- {
- return CryptoHelper.AesInvMixColumns(value);
- }
-
- [UnmanagedCallersOnly]
- public static V128 MixColumns(V128 value)
- {
- return CryptoHelper.AesMixColumns(value);
- }
- #endregion
-
- #region "Sha1"
- [UnmanagedCallersOnly]
- public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
- {
- for (int e = 0; e <= 3; e++)
- {
- uint t = ShaChoose(hash_abcd.Extract(1),
- hash_abcd.Extract(2),
- hash_abcd.Extract(3));
-
- hash_e += Rol(hash_abcd.Extract(0), 5) + t + wk.Extract(e);
-
- t = Rol(hash_abcd.Extract(1), 30);
-
- hash_abcd.Insert(1, t);
-
- Rol32_160(ref hash_e, ref hash_abcd);
- }
-
- return hash_abcd;
- }
-
- [UnmanagedCallersOnly]
- public static uint FixedRotate(uint hash_e)
- {
- return hash_e.Rol(30);
- }
-
- [UnmanagedCallersOnly]
- public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
- {
- for (int e = 0; e <= 3; e++)
- {
- uint t = ShaMajority(hash_abcd.Extract(1),
- hash_abcd.Extract(2),
- hash_abcd.Extract(3));
-
- hash_e += Rol(hash_abcd.Extract(0), 5) + t + wk.Extract(e);
-
- t = Rol(hash_abcd.Extract(1), 30);
-
- hash_abcd.Insert(1, t);
-
- Rol32_160(ref hash_e, ref hash_abcd);
- }
-
- return hash_abcd;
- }
-
- [UnmanagedCallersOnly]
- public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
- {
- for (int e = 0; e <= 3; e++)
- {
- uint t = ShaParity(hash_abcd.Extract(1),
- hash_abcd.Extract(2),
- hash_abcd.Extract(3));
-
- hash_e += Rol(hash_abcd.Extract(0), 5) + t + wk.Extract(e);
-
- t = Rol(hash_abcd.Extract(1), 30);
-
- hash_abcd.Insert(1, t);
-
- Rol32_160(ref hash_e, ref hash_abcd);
- }
-
- return hash_abcd;
- }
-
- [UnmanagedCallersOnly]
- public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
- {
- ulong t2 = w4_7.Extract(0);
- ulong t1 = w0_3.Extract(1);
-
- V128 result = new(t1, t2);
-
- return result ^ (w0_3 ^ w8_11);
- }
-
- [UnmanagedCallersOnly]
- public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
- {
- V128 t = tw0_3 ^ (w12_15 >> 32);
-
- uint tE0 = t.Extract(0);
- uint tE1 = t.Extract(1);
- uint tE2 = t.Extract(2);
- uint tE3 = t.Extract(3);
-
- return new V128(tE0.Rol(1), tE1.Rol(1), tE2.Rol(1), tE3.Rol(1) ^ tE0.Rol(2));
- }
-
- private static void Rol32_160(ref uint y, ref V128 x)
- {
- uint xE3 = x.Extract(3);
-
- x <<= 32;
- x.Insert(0, y);
-
- y = xE3;
- }
-
- private static uint ShaChoose(uint x, uint y, uint z)
- {
- return ((y ^ z) & x) ^ z;
- }
-
- private static uint ShaMajority(uint x, uint y, uint z)
- {
- return (x & y) | ((x | y) & z);
- }
-
- private static uint ShaParity(uint x, uint y, uint z)
- {
- return x ^ y ^ z;
- }
-
- private static uint Rol(this uint value, int count)
- {
- return (value << count) | (value >> (32 - count));
- }
- #endregion
-
- #region "Sha256"
- [UnmanagedCallersOnly]
- public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
- {
- return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
- }
-
- [UnmanagedCallersOnly]
- public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
- {
- return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
- }
-
- [UnmanagedCallersOnly]
- public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
- {
- V128 result = new();
-
- for (int e = 0; e <= 3; e++)
- {
- uint elt = (e <= 2 ? w0_3 : w4_7).Extract(e <= 2 ? e + 1 : 0);
-
- elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3);
-
- elt += w0_3.Extract(e);
-
- result.Insert(e, elt);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
- {
- V128 result = new();
-
- ulong t1 = w12_15.Extract(1);
-
- for (int e = 0; e <= 1; e++)
- {
- uint elt = t1.ULongPart(e);
-
- elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
-
- elt += w0_3.Extract(e) + w8_11.Extract(e + 1);
-
- result.Insert(e, elt);
- }
-
- t1 = result.Extract(0);
-
- for (int e = 2; e <= 3; e++)
- {
- uint elt = t1.ULongPart(e - 2);
-
- elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
-
- elt += w0_3.Extract(e) + (e == 2 ? w8_11 : w12_15).Extract(e == 2 ? 3 : 0);
-
- result.Insert(e, elt);
- }
-
- return result;
- }
-
- private static V128 Sha256Hash(V128 x, V128 y, V128 w, bool part1)
- {
- for (int e = 0; e <= 3; e++)
- {
- uint chs = ShaChoose(y.Extract(0),
- y.Extract(1),
- y.Extract(2));
-
- uint maj = ShaMajority(x.Extract(0),
- x.Extract(1),
- x.Extract(2));
-
- uint t1 = y.Extract(3) + ShaHashSigma1(y.Extract(0)) + chs + w.Extract(e);
-
- uint t2 = t1 + x.Extract(3);
-
- x.Insert(3, t2);
-
- t2 = t1 + ShaHashSigma0(x.Extract(0)) + maj;
-
- y.Insert(3, t2);
-
- Rol32_256(ref y, ref x);
- }
-
- return part1 ? x : y;
- }
-
- private static void Rol32_256(ref V128 y, ref V128 x)
- {
- uint yE3 = y.Extract(3);
- uint xE3 = x.Extract(3);
-
- y <<= 32;
- x <<= 32;
-
- y.Insert(0, xE3);
- x.Insert(0, yE3);
- }
-
- private static uint ShaHashSigma0(uint x)
- {
- return x.Ror(2) ^ x.Ror(13) ^ x.Ror(22);
- }
-
- private static uint ShaHashSigma1(uint x)
- {
- return x.Ror(6) ^ x.Ror(11) ^ x.Ror(25);
- }
-
- private static uint Ror(this uint value, int count)
- {
- return (value >> count) | (value << (32 - count));
- }
-
- private static uint Lsr(this uint value, int count)
- {
- return value >> count;
- }
-
- private static uint ULongPart(this ulong value, int part)
- {
- return part == 0
- ? (uint)(value & 0xFFFFFFFFUL)
- : (uint)(value >> 32);
- }
- #endregion
-
- [UnmanagedCallersOnly]
- public static V128 PolynomialMult64_128(ulong op1, ulong op2)
- {
- V128 result = V128.Zero;
-
- V128 op2_128 = new(op2, 0);
-
- for (int i = 0; i < 64; i++)
- {
- if (((op1 >> i) & 1) == 1)
- {
- result ^= op2_128 << i;
- }
- }
-
- return result;
- }
- }
-}
diff --git a/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Aes.cs b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Aes.cs
new file mode 100644
index 000000000..fe133929d
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Aes.cs
@@ -0,0 +1,32 @@
+using ARMeilleure.State;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class SoftFallback
+ {
+ [UnmanagedCallersOnly]
+ public static V128 Decrypt(V128 value, V128 roundKey)
+ {
+ return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Encrypt(V128 value, V128 roundKey)
+ {
+ return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 InverseMixColumns(V128 value)
+ {
+ return CryptoHelper.AesInvMixColumns(value);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 MixColumns(V128 value)
+ {
+ return CryptoHelper.AesMixColumns(value);
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Count.cs b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Count.cs
new file mode 100644
index 000000000..cbe2a79ca
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Count.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class SoftFallback
+ {
+ [UnmanagedCallersOnly]
+ public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
+ {
+ value ^= value >> 1;
+
+ int highBit = size - 2;
+
+ for (int bit = highBit; bit >= 0; bit--)
+ {
+ if (((int)(value >> bit) & 0b1) != 0)
+ {
+ return (ulong)(highBit - bit);
+ }
+ }
+
+ return (ulong)(size - 1);
+ }
+
+ private static ReadOnlySpan ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
+
+ [UnmanagedCallersOnly]
+ public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
+ {
+ if (value == 0ul)
+ {
+ return (ulong)size;
+ }
+
+ int nibbleIdx = size;
+ int preCount, count = 0;
+
+ do
+ {
+ nibbleIdx -= 4;
+ preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111];
+ count += preCount;
+ }
+ while (preCount == 4);
+
+ return (ulong)count;
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Crc32.cs b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Crc32.cs
new file mode 100644
index 000000000..505cb032f
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Crc32.cs
@@ -0,0 +1,74 @@
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class SoftFallback
+ {
+ private const uint Crc32RevPoly = 0xedb88320;
+ private const uint Crc32cRevPoly = 0x82f63b78;
+
+ [UnmanagedCallersOnly]
+ public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
+ [UnmanagedCallersOnly]
+ public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
+ [UnmanagedCallersOnly]
+ public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
+ [UnmanagedCallersOnly]
+ public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
+
+ [UnmanagedCallersOnly]
+ public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
+ [UnmanagedCallersOnly]
+ public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
+ [UnmanagedCallersOnly]
+ public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
+ [UnmanagedCallersOnly]
+ public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
+
+ private static uint Crc32h(uint crc, uint poly, ushort val)
+ {
+ crc = Crc32(crc, poly, (byte)(val >> 0));
+ crc = Crc32(crc, poly, (byte)(val >> 8));
+
+ return crc;
+ }
+
+ private static uint Crc32w(uint crc, uint poly, uint val)
+ {
+ crc = Crc32(crc, poly, (byte)(val >> 0));
+ crc = Crc32(crc, poly, (byte)(val >> 8));
+ crc = Crc32(crc, poly, (byte)(val >> 16));
+ crc = Crc32(crc, poly, (byte)(val >> 24));
+
+ return crc;
+ }
+
+ private static uint Crc32x(uint crc, uint poly, ulong val)
+ {
+ crc = Crc32(crc, poly, (byte)(val >> 0));
+ crc = Crc32(crc, poly, (byte)(val >> 8));
+ crc = Crc32(crc, poly, (byte)(val >> 16));
+ crc = Crc32(crc, poly, (byte)(val >> 24));
+ crc = Crc32(crc, poly, (byte)(val >> 32));
+ crc = Crc32(crc, poly, (byte)(val >> 40));
+ crc = Crc32(crc, poly, (byte)(val >> 48));
+ crc = Crc32(crc, poly, (byte)(val >> 56));
+
+ return crc;
+ }
+
+ private static uint Crc32(uint crc, uint poly, byte val)
+ {
+ crc ^= val;
+
+ for (int bit = 7; bit >= 0; bit--)
+ {
+ uint mask = (uint)(-(int)(crc & 1));
+
+ crc = (crc >> 1) ^ (poly & mask);
+ }
+
+ return crc;
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Saturation.cs b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Saturation.cs
new file mode 100644
index 000000000..2cbea1560
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Saturation.cs
@@ -0,0 +1,103 @@
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class SoftFallback
+ {
+ [UnmanagedCallersOnly]
+ public static int SatF32ToS32(float value)
+ {
+ if (float.IsNaN(value))
+ {
+ return 0;
+ }
+
+ return value >= int.MaxValue ? int.MaxValue :
+ value <= int.MinValue ? int.MinValue : (int)value;
+ }
+
+ [UnmanagedCallersOnly]
+ public static long SatF32ToS64(float value)
+ {
+ if (float.IsNaN(value))
+ {
+ return 0;
+ }
+
+ return value >= long.MaxValue ? long.MaxValue :
+ value <= long.MinValue ? long.MinValue : (long)value;
+ }
+
+ [UnmanagedCallersOnly]
+ public static uint SatF32ToU32(float value)
+ {
+ if (float.IsNaN(value))
+ {
+ return 0;
+ }
+
+ return value >= uint.MaxValue ? uint.MaxValue :
+ value <= uint.MinValue ? uint.MinValue : (uint)value;
+ }
+
+ [UnmanagedCallersOnly]
+ public static ulong SatF32ToU64(float value)
+ {
+ if (float.IsNaN(value))
+ {
+ return 0;
+ }
+
+ return value >= ulong.MaxValue ? ulong.MaxValue :
+ value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
+ }
+
+ [UnmanagedCallersOnly]
+ public static int SatF64ToS32(double value)
+ {
+ if (double.IsNaN(value))
+ {
+ return 0;
+ }
+
+ return value >= int.MaxValue ? int.MaxValue :
+ value <= int.MinValue ? int.MinValue : (int)value;
+ }
+
+ [UnmanagedCallersOnly]
+ public static long SatF64ToS64(double value)
+ {
+ if (double.IsNaN(value))
+ {
+ return 0;
+ }
+
+ return value >= long.MaxValue ? long.MaxValue :
+ value <= long.MinValue ? long.MinValue : (long)value;
+ }
+
+ [UnmanagedCallersOnly]
+ public static uint SatF64ToU32(double value)
+ {
+ if (double.IsNaN(value))
+ {
+ return 0;
+ }
+
+ return value >= uint.MaxValue ? uint.MaxValue :
+ value <= uint.MinValue ? uint.MinValue : (uint)value;
+ }
+
+ [UnmanagedCallersOnly]
+ public static ulong SatF64ToU64(double value)
+ {
+ if (double.IsNaN(value))
+ {
+ return 0;
+ }
+
+ return value >= ulong.MaxValue ? ulong.MaxValue :
+ value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha1.cs b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha1.cs
new file mode 100644
index 000000000..62aecced7
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha1.cs
@@ -0,0 +1,131 @@
+using ARMeilleure.State;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class SoftFallback
+ {
+ [UnmanagedCallersOnly]
+ public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
+ {
+ for (int e = 0; e <= 3; e++)
+ {
+ uint t = ShaChoose(hash_abcd.Extract(1),
+ hash_abcd.Extract(2),
+ hash_abcd.Extract(3));
+
+ hash_e += Rol(hash_abcd.Extract(0), 5) + t + wk.Extract(e);
+
+ t = Rol(hash_abcd.Extract(1), 30);
+
+ hash_abcd.Insert(1, t);
+
+ Rol32_160(ref hash_e, ref hash_abcd);
+ }
+
+ return hash_abcd;
+ }
+
+ [UnmanagedCallersOnly]
+ public static uint FixedRotate(uint hash_e)
+ {
+ return hash_e.Rol(30);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
+ {
+ for (int e = 0; e <= 3; e++)
+ {
+ uint t = ShaMajority(hash_abcd.Extract(1),
+ hash_abcd.Extract(2),
+ hash_abcd.Extract(3));
+
+ hash_e += Rol(hash_abcd.Extract(0), 5) + t + wk.Extract(e);
+
+ t = Rol(hash_abcd.Extract(1), 30);
+
+ hash_abcd.Insert(1, t);
+
+ Rol32_160(ref hash_e, ref hash_abcd);
+ }
+
+ return hash_abcd;
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
+ {
+ for (int e = 0; e <= 3; e++)
+ {
+ uint t = ShaParity(hash_abcd.Extract(1),
+ hash_abcd.Extract(2),
+ hash_abcd.Extract(3));
+
+ hash_e += Rol(hash_abcd.Extract(0), 5) + t + wk.Extract(e);
+
+ t = Rol(hash_abcd.Extract(1), 30);
+
+ hash_abcd.Insert(1, t);
+
+ Rol32_160(ref hash_e, ref hash_abcd);
+ }
+
+ return hash_abcd;
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
+ {
+ ulong t2 = w4_7.Extract(0);
+ ulong t1 = w0_3.Extract(1);
+
+ V128 result = new(t1, t2);
+
+ return result ^ (w0_3 ^ w8_11);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
+ {
+ V128 t = tw0_3 ^ (w12_15 >> 32);
+
+ uint tE0 = t.Extract(0);
+ uint tE1 = t.Extract(1);
+ uint tE2 = t.Extract(2);
+ uint tE3 = t.Extract(3);
+
+ return new V128(tE0.Rol(1), tE1.Rol(1), tE2.Rol(1), tE3.Rol(1) ^ tE0.Rol(2));
+ }
+
+ private static void Rol32_160(ref uint y, ref V128 x)
+ {
+ uint xE3 = x.Extract(3);
+
+ x <<= 32;
+ x.Insert(0, y);
+
+ y = xE3;
+ }
+
+ private static uint ShaChoose(uint x, uint y, uint z)
+ {
+ return ((y ^ z) & x) ^ z;
+ }
+
+ private static uint ShaMajority(uint x, uint y, uint z)
+ {
+ return (x & y) | ((x | y) & z);
+ }
+
+ private static uint ShaParity(uint x, uint y, uint z)
+ {
+ return x ^ y ^ z;
+ }
+
+ private static uint Rol(this uint value, int count)
+ {
+ return (value << count) | (value >> (32 - count));
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha256.cs b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha256.cs
new file mode 100644
index 000000000..9ce5ec5f9
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Sha256.cs
@@ -0,0 +1,140 @@
+using ARMeilleure.State;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class SoftFallback
+ {
+ [UnmanagedCallersOnly]
+ public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
+ {
+ return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
+ {
+ return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
+ {
+ V128 result = new();
+
+ for (int e = 0; e <= 3; e++)
+ {
+ uint elt = (e <= 2 ? w0_3 : w4_7).Extract(e <= 2 ? e + 1 : 0);
+
+ elt = elt.Ror(7) ^ elt.Ror(18) ^ elt.Lsr(3);
+
+ elt += w0_3.Extract(e);
+
+ result.Insert(e, elt);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
+ {
+ V128 result = new();
+
+ ulong t1 = w12_15.Extract(1);
+
+ for (int e = 0; e <= 1; e++)
+ {
+ uint elt = t1.ULongPart(e);
+
+ elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
+
+ elt += w0_3.Extract(e) + w8_11.Extract(e + 1);
+
+ result.Insert(e, elt);
+ }
+
+ t1 = result.Extract(0);
+
+ for (int e = 2; e <= 3; e++)
+ {
+ uint elt = t1.ULongPart(e - 2);
+
+ elt = elt.Ror(17) ^ elt.Ror(19) ^ elt.Lsr(10);
+
+ elt += w0_3.Extract(e) + (e == 2 ? w8_11 : w12_15).Extract(e == 2 ? 3 : 0);
+
+ result.Insert(e, elt);
+ }
+
+ return result;
+ }
+
+ private static V128 Sha256Hash(V128 x, V128 y, V128 w, bool part1)
+ {
+ for (int e = 0; e <= 3; e++)
+ {
+ uint chs = ShaChoose(y.Extract(0),
+ y.Extract(1),
+ y.Extract(2));
+
+ uint maj = ShaMajority(x.Extract(0),
+ x.Extract(1),
+ x.Extract(2));
+
+ uint t1 = y.Extract(3) + ShaHashSigma1(y.Extract(0)) + chs + w.Extract(e);
+
+ uint t2 = t1 + x.Extract(3);
+
+ x.Insert(3, t2);
+
+ t2 = t1 + ShaHashSigma0(x.Extract(0)) + maj;
+
+ y.Insert(3, t2);
+
+ Rol32_256(ref y, ref x);
+ }
+
+ return part1 ? x : y;
+ }
+
+ private static void Rol32_256(ref V128 y, ref V128 x)
+ {
+ uint yE3 = y.Extract(3);
+ uint xE3 = x.Extract(3);
+
+ y <<= 32;
+ x <<= 32;
+
+ y.Insert(0, xE3);
+ x.Insert(0, yE3);
+ }
+
+ private static uint ShaHashSigma0(uint x)
+ {
+ return x.Ror(2) ^ x.Ror(13) ^ x.Ror(22);
+ }
+
+ private static uint ShaHashSigma1(uint x)
+ {
+ return x.Ror(6) ^ x.Ror(11) ^ x.Ror(25);
+ }
+
+ private static uint Ror(this uint value, int count)
+ {
+ return (value >> count) | (value << (32 - count));
+ }
+
+ private static uint Lsr(this uint value, int count)
+ {
+ return value >> count;
+ }
+
+ private static uint ULongPart(this ulong value, int part)
+ {
+ return part == 0
+ ? (uint)(value & 0xFFFFFFFFUL)
+ : (uint)(value >> 32);
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.ShrImm64.cs b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.ShrImm64.cs
new file mode 100644
index 000000000..063b2c939
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.ShrImm64.cs
@@ -0,0 +1,93 @@
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class SoftFallback
+ {
+ [UnmanagedCallersOnly]
+ public static long SignedShrImm64(long value, long roundConst, int shift)
+ {
+ if (roundConst == 0L)
+ {
+ if (shift <= 63)
+ {
+ return value >> shift;
+ }
+ else /* if (shift == 64) */
+ {
+ if (value < 0L)
+ {
+ return -1L;
+ }
+ else /* if (value >= 0L) */
+ {
+ return 0L;
+ }
+ }
+ }
+ else /* if (roundConst == 1L << (shift - 1)) */
+ {
+ if (shift <= 63)
+ {
+ long add = value + roundConst;
+
+ if ((~value & (value ^ add)) < 0L)
+ {
+ return (long)((ulong)add >> shift);
+ }
+ else
+ {
+ return add >> shift;
+ }
+ }
+ else /* if (shift == 64) */
+ {
+ return 0L;
+ }
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
+ {
+ if (roundConst == 0L)
+ {
+ if (shift <= 63)
+ {
+ return value >> shift;
+ }
+ else /* if (shift == 64) */
+ {
+ return 0UL;
+ }
+ }
+ else /* if (roundConst == 1L << (shift - 1)) */
+ {
+ ulong add = value + (ulong)roundConst;
+
+ if ((add < value) && (add < (ulong)roundConst))
+ {
+ if (shift <= 63)
+ {
+ return (add >> shift) | (0x8000000000000000UL >> (shift - 1));
+ }
+ else /* if (shift == 64) */
+ {
+ return 1UL;
+ }
+ }
+ else
+ {
+ if (shift <= 63)
+ {
+ return add >> shift;
+ }
+ else /* if (shift == 64) */
+ {
+ return 0UL;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Table.cs b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Table.cs
new file mode 100644
index 000000000..61fa178df
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.Table.cs
@@ -0,0 +1,88 @@
+using ARMeilleure.State;
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class SoftFallback
+ {
+ [UnmanagedCallersOnly]
+ public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
+ {
+ return TblOrTbx(default, vector, bytes, tb0);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
+ {
+ return TblOrTbx(default, vector, bytes, tb0, tb1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
+ {
+ return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
+ {
+ return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
+ {
+ return TblOrTbx(dest, vector, bytes, tb0);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
+ {
+ return TblOrTbx(dest, vector, bytes, tb0, tb1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
+ {
+ return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
+ }
+
+ [UnmanagedCallersOnly]
+ public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
+ {
+ return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
+ }
+
+ private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params ReadOnlySpan tb)
+ {
+ byte[] res = new byte[16];
+
+ if (dest != default)
+ {
+ Buffer.BlockCopy(dest.ToArray(), 0, res, 0, bytes);
+ }
+
+ byte[] table = new byte[tb.Length * 16];
+
+ for (byte index = 0; index < tb.Length; index++)
+ {
+ Buffer.BlockCopy(tb[index].ToArray(), 0, table, index * 16, 16);
+ }
+
+ byte[] v = vector.ToArray();
+
+ for (byte index = 0; index < bytes; index++)
+ {
+ byte tblIndex = v[index];
+
+ if (tblIndex < table.Length)
+ {
+ res[index] = table[tblIndex];
+ }
+ }
+
+ return new V128(res);
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.cs b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.cs
new file mode 100644
index 000000000..a5baae782
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFallback/SoftFallback.cs
@@ -0,0 +1,26 @@
+using ARMeilleure.State;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class SoftFallback
+ {
+ [UnmanagedCallersOnly]
+ public static V128 PolynomialMult64_128(ulong op1, ulong op2)
+ {
+ V128 result = V128.Zero;
+
+ V128 op2_128 = new(op2, 0);
+
+ for (int i = 0; i < 64; i++)
+ {
+ if (((op1 >> i) & 1) == 1)
+ {
+ result ^= op2_128 << i;
+ }
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFloat.cs b/src/ARMeilleure/Instructions/SoftFloat.cs
deleted file mode 100644
index ccc45cc64..000000000
--- a/src/ARMeilleure/Instructions/SoftFloat.cs
+++ /dev/null
@@ -1,3735 +0,0 @@
-using ARMeilleure.State;
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Instructions
-{
- static class SoftFloat
- {
- static SoftFloat()
- {
- RecipEstimateTable = BuildRecipEstimateTable();
- RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
- }
-
- public static readonly byte[] RecipEstimateTable;
- public static readonly byte[] RecipSqrtEstimateTable;
-
- private static byte[] BuildRecipEstimateTable()
- {
- byte[] tbl = new byte[256];
-
- for (int idx = 0; idx < 256; idx++)
- {
- uint src = (uint)idx + 256u;
-
- Debug.Assert(src is >= 256u and < 512u);
-
- src = (src << 1) + 1u;
-
- uint aux = (1u << 19) / src;
-
- uint dst = (aux + 1u) >> 1;
-
- Debug.Assert(dst is >= 256u and < 512u);
-
- tbl[idx] = (byte)(dst - 256u);
- }
-
- return tbl;
- }
-
- private static byte[] BuildRecipSqrtEstimateTable()
- {
- byte[] tbl = new byte[384];
-
- for (int idx = 0; idx < 384; idx++)
- {
- uint src = (uint)idx + 128u;
-
- Debug.Assert(src is >= 128u and < 512u);
-
- if (src < 256u)
- {
- src = (src << 1) + 1u;
- }
- else
- {
- src = (src >> 1) << 1;
- src = (src + 1u) << 1;
- }
-
- uint aux = 512u;
-
- while (src * (aux + 1u) * (aux + 1u) < (1u << 28))
- {
- aux++;
- }
-
- uint dst = (aux + 1u) >> 1;
-
- Debug.Assert(dst is >= 256u and < 512u);
-
- tbl[idx] = (byte)(dst - 256u);
- }
-
- return tbl;
- }
-
- public static void FPProcessException(FPException exc, ExecutionContext context)
- {
- FPProcessException(exc, context, context.Fpcr);
- }
-
- public static void FPProcessException(FPException exc, ExecutionContext context, FPCR fpcr)
- {
- int enable = (int)exc + 8;
-
- if ((fpcr & (FPCR)(1 << enable)) != 0)
- {
- throw new NotImplementedException("Floating-point trap handling.");
- }
- else
- {
- context.Fpsr |= (FPSR)(1 << (int)exc);
- }
- }
-
- public static FPRoundingMode GetRoundingMode(this FPCR fpcr)
- {
- const int RModeShift = 22;
-
- return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u);
- }
- }
-
- static class SoftFloat16
- {
- public static ushort FPDefaultNaN()
- {
- return (ushort)0x7E00u;
- }
-
- public static ushort FPInfinity(bool sign)
- {
- return sign ? (ushort)0xFC00u : (ushort)0x7C00u;
- }
-
- public static ushort FPZero(bool sign)
- {
- return sign ? (ushort)0x8000u : (ushort)0x0000u;
- }
-
- public static ushort FPMaxNormal(bool sign)
- {
- return sign ? (ushort)0xFBFFu : (ushort)0x7BFFu;
- }
-
- public static double FPUnpackCv(
- this ushort valueBits,
- out FPType type,
- out bool sign,
- ExecutionContext context)
- {
- sign = (~(uint)valueBits & 0x8000u) == 0u;
-
- uint exp16 = ((uint)valueBits & 0x7C00u) >> 10;
- uint frac16 = (uint)valueBits & 0x03FFu;
-
- double real;
-
- if (exp16 == 0u)
- {
- if (frac16 == 0u)
- {
- type = FPType.Zero;
- real = 0d;
- }
- else
- {
- type = FPType.Nonzero; // Subnormal.
- real = Math.Pow(2d, -14) * ((double)frac16 * Math.Pow(2d, -10));
- }
- }
- else if (exp16 == 0x1Fu && (context.Fpcr & FPCR.Ahp) == 0)
- {
- if (frac16 == 0u)
- {
- type = FPType.Infinity;
- real = Math.Pow(2d, 1000);
- }
- else
- {
- type = (~frac16 & 0x0200u) == 0u ? FPType.QNaN : FPType.SNaN;
- real = 0d;
- }
- }
- else
- {
- type = FPType.Nonzero; // Normal.
- real = Math.Pow(2d, (int)exp16 - 15) * (1d + (double)frac16 * Math.Pow(2d, -10));
- }
-
- return sign ? -real : real;
- }
-
- public static ushort FPRoundCv(double real, ExecutionContext context)
- {
- const int MinimumExp = -14;
-
- const int E = 5;
- const int F = 10;
-
- bool sign;
- double mantissa;
-
- if (real < 0d)
- {
- sign = true;
- mantissa = -real;
- }
- else
- {
- sign = false;
- mantissa = real;
- }
-
- int exponent = 0;
-
- while (mantissa < 1d)
- {
- mantissa *= 2d;
- exponent--;
- }
-
- while (mantissa >= 2d)
- {
- mantissa /= 2d;
- exponent++;
- }
-
- uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
-
- if (biasedExp == 0u)
- {
- mantissa /= Math.Pow(2d, MinimumExp - exponent);
- }
-
- uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
- double error = mantissa * Math.Pow(2d, F) - (double)intMant;
-
- if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
- {
- SoftFloat.FPProcessException(FPException.Underflow, context);
- }
-
- bool overflowToInf;
- bool roundUp;
-
- switch (context.Fpcr.GetRoundingMode())
- {
- case FPRoundingMode.ToNearest:
- roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
- overflowToInf = true;
- break;
-
- case FPRoundingMode.TowardsPlusInfinity:
- roundUp = (error != 0d && !sign);
- overflowToInf = !sign;
- break;
-
- case FPRoundingMode.TowardsMinusInfinity:
- roundUp = (error != 0d && sign);
- overflowToInf = sign;
- break;
-
- case FPRoundingMode.TowardsZero:
- roundUp = false;
- overflowToInf = false;
- break;
-
- default:
- throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.GetRoundingMode()}\".");
- }
-
- if (roundUp)
- {
- intMant++;
-
- if (intMant == 1u << F)
- {
- biasedExp = 1u;
- }
-
- if (intMant == 1u << (F + 1))
- {
- biasedExp++;
- intMant >>= 1;
- }
- }
-
- ushort resultBits;
-
- if ((context.Fpcr & FPCR.Ahp) == 0)
- {
- if (biasedExp >= (1u << E) - 1u)
- {
- resultBits = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
-
- SoftFloat.FPProcessException(FPException.Overflow, context);
-
- error = 1d;
- }
- else
- {
- resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
- }
- }
- else
- {
- if (biasedExp >= 1u << E)
- {
- resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context);
-
- error = 0d;
- }
- else
- {
- resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
- }
- }
-
- if (error != 0d)
- {
- SoftFloat.FPProcessException(FPException.Inexact, context);
- }
-
- return resultBits;
- }
- }
-
- static class SoftFloat16_32
- {
- [UnmanagedCallersOnly]
- public static float FPConvert(ushort valueBits)
- {
- ExecutionContext context = NativeInterface.GetContext();
-
- double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
-
- float result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- if ((context.Fpcr & FPCR.Dn) != 0)
- {
- result = SoftFloat32.FPDefaultNaN();
- }
- else
- {
- result = FPConvertNaN(valueBits);
- }
-
- if (type == FPType.SNaN)
- {
- SoftFloat.FPProcessException(FPException.InvalidOp, context);
- }
- }
- else if (type == FPType.Infinity)
- {
- result = SoftFloat32.FPInfinity(sign);
- }
- else if (type == FPType.Zero)
- {
- result = SoftFloat32.FPZero(sign);
- }
- else
- {
- result = FPRoundCv(real, context);
- }
-
- return result;
- }
-
- private static float FPRoundCv(double real, ExecutionContext context)
- {
- const int MinimumExp = -126;
-
- const int E = 8;
- const int F = 23;
-
- bool sign;
- double mantissa;
-
- if (real < 0d)
- {
- sign = true;
- mantissa = -real;
- }
- else
- {
- sign = false;
- mantissa = real;
- }
-
- int exponent = 0;
-
- while (mantissa < 1d)
- {
- mantissa *= 2d;
- exponent--;
- }
-
- while (mantissa >= 2d)
- {
- mantissa /= 2d;
- exponent++;
- }
-
- if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
- {
- context.Fpsr |= FPSR.Ufc;
-
- return SoftFloat32.FPZero(sign);
- }
-
- uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
-
- if (biasedExp == 0u)
- {
- mantissa /= Math.Pow(2d, MinimumExp - exponent);
- }
-
- uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
- double error = mantissa * Math.Pow(2d, F) - (double)intMant;
-
- if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
- {
- SoftFloat.FPProcessException(FPException.Underflow, context);
- }
-
- bool overflowToInf;
- bool roundUp;
-
- switch (context.Fpcr.GetRoundingMode())
- {
- case FPRoundingMode.ToNearest:
- roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
- overflowToInf = true;
- break;
-
- case FPRoundingMode.TowardsPlusInfinity:
- roundUp = (error != 0d && !sign);
- overflowToInf = !sign;
- break;
-
- case FPRoundingMode.TowardsMinusInfinity:
- roundUp = (error != 0d && sign);
- overflowToInf = sign;
- break;
-
- case FPRoundingMode.TowardsZero:
- roundUp = false;
- overflowToInf = false;
- break;
-
- default:
- throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.GetRoundingMode()}\".");
- }
-
- if (roundUp)
- {
- intMant++;
-
- if (intMant == 1u << F)
- {
- biasedExp = 1u;
- }
-
- if (intMant == 1u << (F + 1))
- {
- biasedExp++;
- intMant >>= 1;
- }
- }
-
- float result;
-
- if (biasedExp >= (1u << E) - 1u)
- {
- result = overflowToInf ? SoftFloat32.FPInfinity(sign) : SoftFloat32.FPMaxNormal(sign);
-
- SoftFloat.FPProcessException(FPException.Overflow, context);
-
- error = 1d;
- }
- else
- {
- result = BitConverter.Int32BitsToSingle(
- (int)((sign ? 1u : 0u) << 31 | (biasedExp & 0xFFu) << 23 | (intMant & 0x007FFFFFu)));
- }
-
- if (error != 0d)
- {
- SoftFloat.FPProcessException(FPException.Inexact, context);
- }
-
- return result;
- }
-
- private static float FPConvertNaN(ushort valueBits)
- {
- return BitConverter.Int32BitsToSingle(
- (int)(((uint)valueBits & 0x8000u) << 16 | 0x7FC00000u | ((uint)valueBits & 0x01FFu) << 13));
- }
- }
-
- static class SoftFloat16_64
- {
- [UnmanagedCallersOnly]
- public static double FPConvert(ushort valueBits)
- {
- ExecutionContext context = NativeInterface.GetContext();
-
- double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
-
- double result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- if ((context.Fpcr & FPCR.Dn) != 0)
- {
- result = SoftFloat64.FPDefaultNaN();
- }
- else
- {
- result = FPConvertNaN(valueBits);
- }
-
- if (type == FPType.SNaN)
- {
- SoftFloat.FPProcessException(FPException.InvalidOp, context);
- }
- }
- else if (type == FPType.Infinity)
- {
- result = SoftFloat64.FPInfinity(sign);
- }
- else if (type == FPType.Zero)
- {
- result = SoftFloat64.FPZero(sign);
- }
- else
- {
- result = FPRoundCv(real, context);
- }
-
- return result;
- }
-
- private static double FPRoundCv(double real, ExecutionContext context)
- {
- const int MinimumExp = -1022;
-
- const int E = 11;
- const int F = 52;
-
- bool sign;
- double mantissa;
-
- if (real < 0d)
- {
- sign = true;
- mantissa = -real;
- }
- else
- {
- sign = false;
- mantissa = real;
- }
-
- int exponent = 0;
-
- while (mantissa < 1d)
- {
- mantissa *= 2d;
- exponent--;
- }
-
- while (mantissa >= 2d)
- {
- mantissa /= 2d;
- exponent++;
- }
-
- if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
- {
- context.Fpsr |= FPSR.Ufc;
-
- return SoftFloat64.FPZero(sign);
- }
-
- uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
-
- if (biasedExp == 0u)
- {
- mantissa /= Math.Pow(2d, MinimumExp - exponent);
- }
-
- ulong intMant = (ulong)Math.Floor(mantissa * Math.Pow(2d, F));
- double error = mantissa * Math.Pow(2d, F) - (double)intMant;
-
- if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
- {
- SoftFloat.FPProcessException(FPException.Underflow, context);
- }
-
- bool overflowToInf;
- bool roundUp;
-
- switch (context.Fpcr.GetRoundingMode())
- {
- case FPRoundingMode.ToNearest:
- roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
- overflowToInf = true;
- break;
-
- case FPRoundingMode.TowardsPlusInfinity:
- roundUp = (error != 0d && !sign);
- overflowToInf = !sign;
- break;
-
- case FPRoundingMode.TowardsMinusInfinity:
- roundUp = (error != 0d && sign);
- overflowToInf = sign;
- break;
-
- case FPRoundingMode.TowardsZero:
- roundUp = false;
- overflowToInf = false;
- break;
-
- default:
- throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.GetRoundingMode()}\".");
- }
-
- if (roundUp)
- {
- intMant++;
-
- if (intMant == 1ul << F)
- {
- biasedExp = 1u;
- }
-
- if (intMant == 1ul << (F + 1))
- {
- biasedExp++;
- intMant >>= 1;
- }
- }
-
- double result;
-
- if (biasedExp >= (1u << E) - 1u)
- {
- result = overflowToInf ? SoftFloat64.FPInfinity(sign) : SoftFloat64.FPMaxNormal(sign);
-
- SoftFloat.FPProcessException(FPException.Overflow, context);
-
- error = 1d;
- }
- else
- {
- result = BitConverter.Int64BitsToDouble(
- (long)((sign ? 1ul : 0ul) << 63 | (biasedExp & 0x7FFul) << 52 | (intMant & 0x000FFFFFFFFFFFFFul)));
- }
-
- if (error != 0d)
- {
- SoftFloat.FPProcessException(FPException.Inexact, context);
- }
-
- return result;
- }
-
- private static double FPConvertNaN(ushort valueBits)
- {
- return BitConverter.Int64BitsToDouble(
- (long)(((ulong)valueBits & 0x8000ul) << 48 | 0x7FF8000000000000ul | ((ulong)valueBits & 0x01FFul) << 42));
- }
- }
-
- static class SoftFloat32_16
- {
- [UnmanagedCallersOnly]
- public static ushort FPConvert(float value)
- {
- ExecutionContext context = NativeInterface.GetContext();
-
- double real = value.FPUnpackCv(out FPType type, out bool sign, out uint valueBits, context);
-
- bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
-
- ushort resultBits;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- if (altHp)
- {
- resultBits = SoftFloat16.FPZero(sign);
- }
- else if ((context.Fpcr & FPCR.Dn) != 0)
- {
- resultBits = SoftFloat16.FPDefaultNaN();
- }
- else
- {
- resultBits = FPConvertNaN(valueBits);
- }
-
- if (type == FPType.SNaN || altHp)
- {
- SoftFloat.FPProcessException(FPException.InvalidOp, context);
- }
- }
- else if (type == FPType.Infinity)
- {
- if (altHp)
- {
- resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context);
- }
- else
- {
- resultBits = SoftFloat16.FPInfinity(sign);
- }
- }
- else if (type == FPType.Zero)
- {
- resultBits = SoftFloat16.FPZero(sign);
- }
- else
- {
- resultBits = SoftFloat16.FPRoundCv(real, context);
- }
-
- return resultBits;
- }
-
- private static double FPUnpackCv(
- this float value,
- out FPType type,
- out bool sign,
- out uint valueBits,
- ExecutionContext context)
- {
- valueBits = (uint)BitConverter.SingleToInt32Bits(value);
-
- sign = (~valueBits & 0x80000000u) == 0u;
-
- uint exp32 = (valueBits & 0x7F800000u) >> 23;
- uint frac32 = valueBits & 0x007FFFFFu;
-
- double real;
-
- if (exp32 == 0u)
- {
- if (frac32 == 0u || (context.Fpcr & FPCR.Fz) != 0)
- {
- type = FPType.Zero;
- real = 0d;
-
- if (frac32 != 0u)
- {
- SoftFloat.FPProcessException(FPException.InputDenorm, context);
- }
- }
- else
- {
- type = FPType.Nonzero; // Subnormal.
- real = Math.Pow(2d, -126) * ((double)frac32 * Math.Pow(2d, -23));
- }
- }
- else if (exp32 == 0xFFu)
- {
- if (frac32 == 0u)
- {
- type = FPType.Infinity;
- real = Math.Pow(2d, 1000);
- }
- else
- {
- type = (~frac32 & 0x00400000u) == 0u ? FPType.QNaN : FPType.SNaN;
- real = 0d;
- }
- }
- else
- {
- type = FPType.Nonzero; // Normal.
- real = Math.Pow(2d, (int)exp32 - 127) * (1d + (double)frac32 * Math.Pow(2d, -23));
- }
-
- return sign ? -real : real;
- }
-
- private static ushort FPConvertNaN(uint valueBits)
- {
- return (ushort)((valueBits & 0x80000000u) >> 16 | 0x7E00u | (valueBits & 0x003FE000u) >> 13);
- }
- }
-
- static class SoftFloat32
- {
- [UnmanagedCallersOnly]
- public static float FPAdd(float value1, float value2)
- {
- return FPAddFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static float FPAddFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if (inf1 && inf2 && sign1 == !sign2)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if ((inf1 && !sign1) || (inf2 && !sign2))
- {
- result = FPInfinity(false);
- }
- else if ((inf1 && sign1) || (inf2 && sign2))
- {
- result = FPInfinity(true);
- }
- else if (zero1 && zero2 && sign1 == sign2)
- {
- result = FPZero(sign1);
- }
- else
- {
- result = value1 + value2;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static int FPCompare(float value1, float value2, byte signalNaNs)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- int result;
-
- if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
- {
- result = 0b0011;
-
- if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs == 1)
- {
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- }
- else
- {
- if (value1 == value2)
- {
- result = 0b0110;
- }
- else if (value1 < value2)
- {
- result = 0b1000;
- }
- else
- {
- result = 0b0010;
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareEQ(float value1, float value2)
- {
- return FPCompareEQFpscrImpl(value1, value2, false);
- }
-
- private static float FPCompareEQFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- float result;
-
- if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
- {
- result = ZerosOrOnes(false);
-
- if (type1 == FPType.SNaN || type2 == FPType.SNaN)
- {
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- }
- else
- {
- result = ZerosOrOnes(value1 == value2);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareGE(float value1, float value2)
- {
- return FPCompareGEFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static float FPCompareGEFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- float result;
-
- if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
- {
- result = ZerosOrOnes(false);
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else
- {
- result = ZerosOrOnes(value1 >= value2);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareGT(float value1, float value2)
- {
- return FPCompareGTFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static float FPCompareGTFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- float result;
-
- if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
- {
- result = ZerosOrOnes(false);
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else
- {
- result = ZerosOrOnes(value1 > value2);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareLE(float value1, float value2)
- {
- return FPCompareGEFpscrImpl(value2, value1, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareLT(float value1, float value2)
- {
- return FPCompareGTFpscrImpl(value2, value1, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
- }
-
- [UnmanagedCallersOnly]
- public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
- }
-
- [UnmanagedCallersOnly]
- public static float FPDiv(float value1, float value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && inf2) || (zero1 && zero2))
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if (inf1 || zero2)
- {
- result = FPInfinity(sign1 ^ sign2);
-
- if (!inf1)
- {
- SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
- }
- }
- else if (zero1 || inf2)
- {
- result = FPZero(sign1 ^ sign2);
- }
- else
- {
- result = value1 / value2;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPMax(float value1, float value2)
- {
- return FPMaxFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static float FPMaxFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- if (value1 > value2)
- {
- if (type1 == FPType.Infinity)
- {
- result = FPInfinity(sign1);
- }
- else if (type1 == FPType.Zero)
- {
- result = FPZero(sign1 && sign2);
- }
- else
- {
- result = value1;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
- else
- {
- if (type2 == FPType.Infinity)
- {
- result = FPInfinity(sign2);
- }
- else if (type2 == FPType.Zero)
- {
- result = FPZero(sign1 && sign2);
- }
- else
- {
- result = value2;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPMaxNum(float value1, float value2)
- {
- return FPMaxNumFpscrImpl(value1, value2, false);
- }
-
- private static float FPMaxNumFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- if (type1 == FPType.QNaN && type2 != FPType.QNaN)
- {
- value1 = FPInfinity(true);
- }
- else if (type1 != FPType.QNaN && type2 == FPType.QNaN)
- {
- value2 = FPInfinity(true);
- }
-
- return FPMaxFpscrImpl(value1, value2, standardFpscr);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMin(float value1, float value2)
- {
- return FPMinFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static float FPMinFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- if (value1 < value2)
- {
- if (type1 == FPType.Infinity)
- {
- result = FPInfinity(sign1);
- }
- else if (type1 == FPType.Zero)
- {
- result = FPZero(sign1 || sign2);
- }
- else
- {
- result = value1;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
- else
- {
- if (type2 == FPType.Infinity)
- {
- result = FPInfinity(sign2);
- }
- else if (type2 == FPType.Zero)
- {
- result = FPZero(sign1 || sign2);
- }
- else
- {
- result = value2;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPMinNum(float value1, float value2)
- {
- return FPMinNumFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static float FPMinNumFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- if (type1 == FPType.QNaN && type2 != FPType.QNaN)
- {
- value1 = FPInfinity(false);
- }
- else if (type1 != FPType.QNaN && type2 == FPType.QNaN)
- {
- value2 = FPInfinity(false);
- }
-
- return FPMinFpscrImpl(value1, value2, standardFpscr);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMul(float value1, float value2)
- {
- return FPMulFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
- {
- return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static float FPMulFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if (inf1 || inf2)
- {
- result = FPInfinity(sign1 ^ sign2);
- }
- else if (zero1 || zero2)
- {
- result = FPZero(sign1 ^ sign2);
- }
- else
- {
- result = value1 * value2;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPMulAdd(float valueA, float value1, float value2)
- {
- return FPMulAddFpscrImpl(valueA, value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
- {
- return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
- }
-
- private static float FPMulAddFpscrImpl(float valueA, float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- valueA = valueA.FPUnpack(out FPType typeA, out bool signA, out uint addend, context, fpcr);
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- float result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, context, fpcr);
-
- if (typeA == FPType.QNaN && ((inf1 && zero2) || (zero1 && inf2)))
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
-
- if (!done)
- {
- bool infA = typeA == FPType.Infinity;
- bool zeroA = typeA == FPType.Zero;
-
- bool signP = sign1 ^ sign2;
- bool infP = inf1 || inf2;
- bool zeroP = zero1 || zero2;
-
- if ((inf1 && zero2) || (zero1 && inf2) || (infA && infP && signA != signP))
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if ((infA && !signA) || (infP && !signP))
- {
- result = FPInfinity(false);
- }
- else if ((infA && signA) || (infP && signP))
- {
- result = FPInfinity(true);
- }
- else if (zeroA && zeroP && signA == signP)
- {
- result = FPZero(signA);
- }
- else
- {
- result = MathF.FusedMultiplyAdd(value1, value2, valueA);
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPMulSub(float valueA, float value1, float value2)
- {
- value1 = value1.FPNeg();
-
- return FPMulAddFpscrImpl(valueA, value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
- {
- value1 = value1.FPNeg();
-
- return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
- }
-
- [UnmanagedCallersOnly]
- public static float FPMulX(float value1, float value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- result = FPTwo(sign1 ^ sign2);
- }
- else if (inf1 || inf2)
- {
- result = FPInfinity(sign1 ^ sign2);
- }
- else if (zero1 || zero2)
- {
- result = FPZero(sign1 ^ sign2);
- }
- else
- {
- result = value1 * value2;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPNegMulAdd(float valueA, float value1, float value2)
- {
- valueA = valueA.FPNeg();
- value1 = value1.FPNeg();
-
- return FPMulAddFpscrImpl(valueA, value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPNegMulSub(float valueA, float value1, float value2)
- {
- valueA = valueA.FPNeg();
-
- return FPMulAddFpscrImpl(valueA, value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPRecipEstimate(float value)
- {
- return FPRecipEstimateFpscrImpl(value, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
- {
- return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
- }
-
- private static float FPRecipEstimateFpscrImpl(float value, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
-
- float result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- result = FPProcessNaN(type, op, context, fpcr);
- }
- else if (type == FPType.Infinity)
- {
- result = FPZero(sign);
- }
- else if (type == FPType.Zero)
- {
- result = FPInfinity(sign);
-
- SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
- }
- else if (MathF.Abs(value) < MathF.Pow(2f, -128))
- {
- bool overflowToInf = fpcr.GetRoundingMode() switch
- {
- FPRoundingMode.ToNearest => true,
- FPRoundingMode.TowardsPlusInfinity => !sign,
- FPRoundingMode.TowardsMinusInfinity => sign,
- FPRoundingMode.TowardsZero => false,
- _ => throw new ArgumentException($"Invalid rounding mode \"{fpcr.GetRoundingMode()}\"."),
- };
- result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
-
- SoftFloat.FPProcessException(FPException.Overflow, context, fpcr);
- SoftFloat.FPProcessException(FPException.Inexact, context, fpcr);
- }
- else if ((fpcr & FPCR.Fz) != 0 && (MathF.Abs(value) >= MathF.Pow(2f, 126)))
- {
- result = FPZero(sign);
-
- context.Fpsr |= FPSR.Ufc;
- }
- else
- {
- ulong fraction = (ulong)(op & 0x007FFFFFu) << 29;
- uint exp = (op & 0x7F800000u) >> 23;
-
- if (exp == 0u)
- {
- if ((fraction & 0x0008000000000000ul) == 0ul)
- {
- fraction = (fraction & 0x0003FFFFFFFFFFFFul) << 2;
- exp -= 1u;
- }
- else
- {
- fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
- }
- }
-
- uint scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
-
- uint resultExp = 253u - exp;
-
- uint estimate = (uint)SoftFloat.RecipEstimateTable[scaled - 256u] + 256u;
-
- fraction = (ulong)(estimate & 0xFFu) << 44;
-
- if (resultExp == 0u)
- {
- fraction = ((fraction & 0x000FFFFFFFFFFFFEul) | 0x0010000000000000ul) >> 1;
- }
- else if (resultExp + 1u == 0u)
- {
- fraction = ((fraction & 0x000FFFFFFFFFFFFCul) | 0x0010000000000000ul) >> 2;
- resultExp = 0u;
- }
-
- result = BitConverter.Int32BitsToSingle(
- (int)((sign ? 1u : 0u) << 31 | (resultExp & 0xFFu) << 23 | (uint)(fraction >> 29) & 0x007FFFFFu));
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPRecipStep(float value1, float value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.StandardFpcrValue;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- float product;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- product = FPZero(false);
- }
- else
- {
- product = FPMulFpscrImpl(value1, value2, true);
- }
-
- result = FPSubFpscrImpl(FPTwo(false), product, true);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPRecipStepFused(float value1, float value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPNeg();
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- result = FPTwo(false);
- }
- else if (inf1 || inf2)
- {
- result = FPInfinity(sign1 ^ sign2);
- }
- else
- {
- result = MathF.FusedMultiplyAdd(value1, value2, 2f);
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPRecpX(float value)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
-
- float result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- result = FPProcessNaN(type, op, context, fpcr);
- }
- else
- {
- uint notExp = (~op >> 23) & 0xFFu;
- uint maxExp = 0xFEu;
-
- result = BitConverter.Int32BitsToSingle(
- (int)((sign ? 1u : 0u) << 31 | (notExp == 0xFFu ? maxExp : notExp) << 23));
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPRSqrtEstimate(float value)
- {
- return FPRSqrtEstimateFpscrImpl(value, false);
- }
-
- [UnmanagedCallersOnly]
- public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
- {
- return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
- }
-
- private static float FPRSqrtEstimateFpscrImpl(float value, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
-
- float result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- result = FPProcessNaN(type, op, context, fpcr);
- }
- else if (type == FPType.Zero)
- {
- result = FPInfinity(sign);
-
- SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
- }
- else if (sign)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if (type == FPType.Infinity)
- {
- result = FPZero(false);
- }
- else
- {
- ulong fraction = (ulong)(op & 0x007FFFFFu) << 29;
- uint exp = (op & 0x7F800000u) >> 23;
-
- if (exp == 0u)
- {
- while ((fraction & 0x0008000000000000ul) == 0ul)
- {
- fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
- exp -= 1u;
- }
-
- fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
- }
-
- uint scaled;
-
- if ((exp & 1u) == 0u)
- {
- scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
- }
- else
- {
- scaled = (uint)(((fraction & 0x000FE00000000000ul) | 0x0010000000000000ul) >> 45);
- }
-
- uint resultExp = (380u - exp) >> 1;
-
- uint estimate = (uint)SoftFloat.RecipSqrtEstimateTable[scaled - 128u] + 256u;
-
- result = BitConverter.Int32BitsToSingle((int)((resultExp & 0xFFu) << 23 | (estimate & 0xFFu) << 15));
- }
-
- return result;
- }
-
- public static float FPHalvedSub(float value1, float value2, ExecutionContext context, FPCR fpcr)
- {
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if (inf1 && inf2 && sign1 == sign2)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if ((inf1 && !sign1) || (inf2 && sign2))
- {
- result = FPInfinity(false);
- }
- else if ((inf1 && sign1) || (inf2 && !sign2))
- {
- result = FPInfinity(true);
- }
- else if (zero1 && zero2 && sign1 == !sign2)
- {
- result = FPZero(sign1);
- }
- else
- {
- result = (value1 - value2) / 2.0f;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPRSqrtStep(float value1, float value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.StandardFpcrValue;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- float product;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- product = FPZero(false);
- }
- else
- {
- product = FPMulFpscrImpl(value1, value2, true);
- }
-
- result = FPHalvedSub(FPThree(false), product, context, fpcr);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPRSqrtStepFused(float value1, float value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPNeg();
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- result = FPOnePointFive(false);
- }
- else if (inf1 || inf2)
- {
- result = FPInfinity(sign1 ^ sign2);
- }
- else
- {
- result = MathF.FusedMultiplyAdd(value1, value2, 3f) / 2f;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPSqrt(float value)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value = value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
-
- float result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- result = FPProcessNaN(type, op, context, fpcr);
- }
- else if (type == FPType.Zero)
- {
- result = FPZero(sign);
- }
- else if (type == FPType.Infinity && !sign)
- {
- result = FPInfinity(sign);
- }
- else if (sign)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else
- {
- result = MathF.Sqrt(value);
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static float FPSub(float value1, float value2)
- {
- return FPSubFpscrImpl(value1, value2, false);
- }
-
- private static float FPSubFpscrImpl(float value1, float value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
-
- float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if (inf1 && inf2 && sign1 == sign2)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if ((inf1 && !sign1) || (inf2 && sign2))
- {
- result = FPInfinity(false);
- }
- else if ((inf1 && sign1) || (inf2 && !sign2))
- {
- result = FPInfinity(true);
- }
- else if (zero1 && zero2 && sign1 == !sign2)
- {
- result = FPZero(sign1);
- }
- else
- {
- result = value1 - value2;
-
- if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0f);
- }
- }
- }
-
- return result;
- }
-
- public static float FPDefaultNaN()
- {
- return BitConverter.Int32BitsToSingle(0x7fc00000);
- }
-
- public static float FPInfinity(bool sign)
- {
- return sign ? float.NegativeInfinity : float.PositiveInfinity;
- }
-
- public static float FPZero(bool sign)
- {
- return sign ? -0f : +0f;
- }
-
- public static float FPMaxNormal(bool sign)
- {
- return sign ? float.MinValue : float.MaxValue;
- }
-
- private static float FPTwo(bool sign)
- {
- return sign ? -2f : +2f;
- }
-
- private static float FPThree(bool sign)
- {
- return sign ? -3f : +3f;
- }
-
- private static float FPOnePointFive(bool sign)
- {
- return sign ? -1.5f : +1.5f;
- }
-
- private static float FPNeg(this float value)
- {
- return -value;
- }
-
- private static float ZerosOrOnes(bool ones)
- {
- return BitConverter.Int32BitsToSingle(ones ? -1 : 0);
- }
-
- private static float FPUnpack(
- this float value,
- out FPType type,
- out bool sign,
- out uint valueBits,
- ExecutionContext context,
- FPCR fpcr)
- {
- valueBits = (uint)BitConverter.SingleToInt32Bits(value);
-
- sign = (~valueBits & 0x80000000u) == 0u;
-
- if ((valueBits & 0x7F800000u) == 0u)
- {
- if ((valueBits & 0x007FFFFFu) == 0u || (fpcr & FPCR.Fz) != 0)
- {
- type = FPType.Zero;
- value = FPZero(sign);
-
- if ((valueBits & 0x007FFFFFu) != 0u)
- {
- SoftFloat.FPProcessException(FPException.InputDenorm, context, fpcr);
- }
- }
- else
- {
- type = FPType.Nonzero;
- }
- }
- else if ((~valueBits & 0x7F800000u) == 0u)
- {
- if ((valueBits & 0x007FFFFFu) == 0u)
- {
- type = FPType.Infinity;
- }
- else
- {
- type = (~valueBits & 0x00400000u) == 0u ? FPType.QNaN : FPType.SNaN;
- value = FPZero(sign);
- }
- }
- else
- {
- type = FPType.Nonzero;
- }
-
- return value;
- }
-
- private static float FPProcessNaNs(
- FPType type1,
- FPType type2,
- uint op1,
- uint op2,
- out bool done,
- ExecutionContext context,
- FPCR fpcr)
- {
- done = true;
-
- if (type1 == FPType.SNaN)
- {
- return FPProcessNaN(type1, op1, context, fpcr);
- }
- else if (type2 == FPType.SNaN)
- {
- return FPProcessNaN(type2, op2, context, fpcr);
- }
- else if (type1 == FPType.QNaN)
- {
- return FPProcessNaN(type1, op1, context, fpcr);
- }
- else if (type2 == FPType.QNaN)
- {
- return FPProcessNaN(type2, op2, context, fpcr);
- }
-
- done = false;
-
- return FPZero(false);
- }
-
- private static float FPProcessNaNs3(
- FPType type1,
- FPType type2,
- FPType type3,
- uint op1,
- uint op2,
- uint op3,
- out bool done,
- ExecutionContext context,
- FPCR fpcr)
- {
- done = true;
-
- if (type1 == FPType.SNaN)
- {
- return FPProcessNaN(type1, op1, context, fpcr);
- }
- else if (type2 == FPType.SNaN)
- {
- return FPProcessNaN(type2, op2, context, fpcr);
- }
- else if (type3 == FPType.SNaN)
- {
- return FPProcessNaN(type3, op3, context, fpcr);
- }
- else if (type1 == FPType.QNaN)
- {
- return FPProcessNaN(type1, op1, context, fpcr);
- }
- else if (type2 == FPType.QNaN)
- {
- return FPProcessNaN(type2, op2, context, fpcr);
- }
- else if (type3 == FPType.QNaN)
- {
- return FPProcessNaN(type3, op3, context, fpcr);
- }
-
- done = false;
-
- return FPZero(false);
- }
-
- private static float FPProcessNaN(FPType type, uint op, ExecutionContext context, FPCR fpcr)
- {
- if (type == FPType.SNaN)
- {
- op |= 1u << 22;
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
-
- if ((fpcr & FPCR.Dn) != 0)
- {
- return FPDefaultNaN();
- }
-
- return BitConverter.Int32BitsToSingle((int)op);
- }
- }
-
- static class SoftFloat64_16
- {
- [UnmanagedCallersOnly]
- public static ushort FPConvert(double value)
- {
- ExecutionContext context = NativeInterface.GetContext();
-
- double real = value.FPUnpackCv(out FPType type, out bool sign, out ulong valueBits, context);
-
- bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
-
- ushort resultBits;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- if (altHp)
- {
- resultBits = SoftFloat16.FPZero(sign);
- }
- else if ((context.Fpcr & FPCR.Dn) != 0)
- {
- resultBits = SoftFloat16.FPDefaultNaN();
- }
- else
- {
- resultBits = FPConvertNaN(valueBits);
- }
-
- if (type == FPType.SNaN || altHp)
- {
- SoftFloat.FPProcessException(FPException.InvalidOp, context);
- }
- }
- else if (type == FPType.Infinity)
- {
- if (altHp)
- {
- resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context);
- }
- else
- {
- resultBits = SoftFloat16.FPInfinity(sign);
- }
- }
- else if (type == FPType.Zero)
- {
- resultBits = SoftFloat16.FPZero(sign);
- }
- else
- {
- resultBits = SoftFloat16.FPRoundCv(real, context);
- }
-
- return resultBits;
- }
-
- private static double FPUnpackCv(
- this double value,
- out FPType type,
- out bool sign,
- out ulong valueBits,
- ExecutionContext context)
- {
- valueBits = (ulong)BitConverter.DoubleToInt64Bits(value);
-
- sign = (~valueBits & 0x8000000000000000ul) == 0u;
-
- ulong exp64 = (valueBits & 0x7FF0000000000000ul) >> 52;
- ulong frac64 = valueBits & 0x000FFFFFFFFFFFFFul;
-
- double real;
-
- if (exp64 == 0u)
- {
- if (frac64 == 0u || (context.Fpcr & FPCR.Fz) != 0)
- {
- type = FPType.Zero;
- real = 0d;
-
- if (frac64 != 0u)
- {
- SoftFloat.FPProcessException(FPException.InputDenorm, context);
- }
- }
- else
- {
- type = FPType.Nonzero; // Subnormal.
- real = Math.Pow(2d, -1022) * ((double)frac64 * Math.Pow(2d, -52));
- }
- }
- else if (exp64 == 0x7FFul)
- {
- if (frac64 == 0u)
- {
- type = FPType.Infinity;
- real = Math.Pow(2d, 1000000);
- }
- else
- {
- type = (~frac64 & 0x0008000000000000ul) == 0u ? FPType.QNaN : FPType.SNaN;
- real = 0d;
- }
- }
- else
- {
- type = FPType.Nonzero; // Normal.
- real = Math.Pow(2d, (int)exp64 - 1023) * (1d + (double)frac64 * Math.Pow(2d, -52));
- }
-
- return sign ? -real : real;
- }
-
- private static ushort FPConvertNaN(ulong valueBits)
- {
- return (ushort)((valueBits & 0x8000000000000000ul) >> 48 | 0x7E00u | (valueBits & 0x0007FC0000000000ul) >> 42);
- }
- }
-
- static class SoftFloat64
- {
- [UnmanagedCallersOnly]
- public static double FPAdd(double value1, double value2)
- {
- return FPAddFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static double FPAddFpscrImpl(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if (inf1 && inf2 && sign1 == !sign2)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if ((inf1 && !sign1) || (inf2 && !sign2))
- {
- result = FPInfinity(false);
- }
- else if ((inf1 && sign1) || (inf2 && sign2))
- {
- result = FPInfinity(true);
- }
- else if (zero1 && zero2 && sign1 == sign2)
- {
- result = FPZero(sign1);
- }
- else
- {
- result = value1 + value2;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static int FPCompare(double value1, double value2, byte signalNaNs)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- int result;
-
- if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
- {
- result = 0b0011;
-
- if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs == 1)
- {
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- }
- else
- {
- if (value1 == value2)
- {
- result = 0b0110;
- }
- else if (value1 < value2)
- {
- result = 0b1000;
- }
- else
- {
- result = 0b0010;
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareEQ(double value1, double value2)
- {
- return FPCompareEQFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static double FPCompareEQFpscrImpl(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- double result;
-
- if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
- {
- result = ZerosOrOnes(false);
-
- if (type1 == FPType.SNaN || type2 == FPType.SNaN)
- {
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- }
- else
- {
- result = ZerosOrOnes(value1 == value2);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareGE(double value1, double value2)
- {
- return FPCompareGEFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static double FPCompareGEFpscrImpl(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- double result;
-
- if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
- {
- result = ZerosOrOnes(false);
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else
- {
- result = ZerosOrOnes(value1 >= value2);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareGT(double value1, double value2)
- {
- return FPCompareGTFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static double FPCompareGTFpscrImpl(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- double result;
-
- if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
- {
- result = ZerosOrOnes(false);
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else
- {
- result = ZerosOrOnes(value1 > value2);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareLE(double value1, double value2)
- {
- return FPCompareGEFpscrImpl(value2, value1, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareLT(double value1, double value2)
- {
- return FPCompareGTFpscrImpl(value2, value1, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
- }
-
- [UnmanagedCallersOnly]
- public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
- }
-
- [UnmanagedCallersOnly]
- public static double FPDiv(double value1, double value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && inf2) || (zero1 && zero2))
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if (inf1 || zero2)
- {
- result = FPInfinity(sign1 ^ sign2);
-
- if (!inf1)
- {
- SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
- }
- }
- else if (zero1 || inf2)
- {
- result = FPZero(sign1 ^ sign2);
- }
- else
- {
- result = value1 / value2;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPMax(double value1, double value2)
- {
- return FPMaxFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static double FPMaxFpscrImpl(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- if (value1 > value2)
- {
- if (type1 == FPType.Infinity)
- {
- result = FPInfinity(sign1);
- }
- else if (type1 == FPType.Zero)
- {
- result = FPZero(sign1 && sign2);
- }
- else
- {
- result = value1;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
- else
- {
- if (type2 == FPType.Infinity)
- {
- result = FPInfinity(sign2);
- }
- else if (type2 == FPType.Zero)
- {
- result = FPZero(sign1 && sign2);
- }
- else
- {
- result = value2;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPMaxNum(double value1, double value2)
- {
- return FPMaxNumFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static double FPMaxNumFpscrImpl(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- if (type1 == FPType.QNaN && type2 != FPType.QNaN)
- {
- value1 = FPInfinity(true);
- }
- else if (type1 != FPType.QNaN && type2 == FPType.QNaN)
- {
- value2 = FPInfinity(true);
- }
-
- return FPMaxFpscrImpl(value1, value2, standardFpscr);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMin(double value1, double value2)
- {
- return FPMinFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static double FPMinFpscrImpl(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- if (value1 < value2)
- {
- if (type1 == FPType.Infinity)
- {
- result = FPInfinity(sign1);
- }
- else if (type1 == FPType.Zero)
- {
- result = FPZero(sign1 || sign2);
- }
- else
- {
- result = value1;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
- else
- {
- if (type2 == FPType.Infinity)
- {
- result = FPInfinity(sign2);
- }
- else if (type2 == FPType.Zero)
- {
- result = FPZero(sign1 || sign2);
- }
- else
- {
- result = value2;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPMinNum(double value1, double value2)
- {
- return FPMinNumFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static double FPMinNumFpscrImpl(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
- value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
-
- if (type1 == FPType.QNaN && type2 != FPType.QNaN)
- {
- value1 = FPInfinity(false);
- }
- else if (type1 != FPType.QNaN && type2 == FPType.QNaN)
- {
- value2 = FPInfinity(false);
- }
-
- return FPMinFpscrImpl(value1, value2, standardFpscr);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMul(double value1, double value2)
- {
- return FPMulFpscrImpl(value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
- {
- return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
- }
-
- private static double FPMulFpscrImpl(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if (inf1 || inf2)
- {
- result = FPInfinity(sign1 ^ sign2);
- }
- else if (zero1 || zero2)
- {
- result = FPZero(sign1 ^ sign2);
- }
- else
- {
- result = value1 * value2;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPMulAdd(double valueA, double value1, double value2)
- {
- return FPMulAddFpscrImpl(valueA, value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
- {
- return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
- }
-
- private static double FPMulAddFpscrImpl(double valueA, double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- valueA = valueA.FPUnpack(out FPType typeA, out bool signA, out ulong addend, context, fpcr);
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- double result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, context, fpcr);
-
- if (typeA == FPType.QNaN && ((inf1 && zero2) || (zero1 && inf2)))
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
-
- if (!done)
- {
- bool infA = typeA == FPType.Infinity;
- bool zeroA = typeA == FPType.Zero;
-
- bool signP = sign1 ^ sign2;
- bool infP = inf1 || inf2;
- bool zeroP = zero1 || zero2;
-
- if ((inf1 && zero2) || (zero1 && inf2) || (infA && infP && signA != signP))
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if ((infA && !signA) || (infP && !signP))
- {
- result = FPInfinity(false);
- }
- else if ((infA && signA) || (infP && signP))
- {
- result = FPInfinity(true);
- }
- else if (zeroA && zeroP && signA == signP)
- {
- result = FPZero(signA);
- }
- else
- {
- result = Math.FusedMultiplyAdd(value1, value2, valueA);
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPMulSub(double valueA, double value1, double value2)
- {
- value1 = value1.FPNeg();
-
- return FPMulAddFpscrImpl(valueA, value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
- {
- value1 = value1.FPNeg();
-
- return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
- }
-
- [UnmanagedCallersOnly]
- public static double FPMulX(double value1, double value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- result = FPTwo(sign1 ^ sign2);
- }
- else if (inf1 || inf2)
- {
- result = FPInfinity(sign1 ^ sign2);
- }
- else if (zero1 || zero2)
- {
- result = FPZero(sign1 ^ sign2);
- }
- else
- {
- result = value1 * value2;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPNegMulAdd(double valueA, double value1, double value2)
- {
- valueA = valueA.FPNeg();
- value1 = value1.FPNeg();
-
- return FPMulAddFpscrImpl(valueA, value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPNegMulSub(double valueA, double value1, double value2)
- {
- valueA = valueA.FPNeg();
-
- return FPMulAddFpscrImpl(valueA, value1, value2, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPRecipEstimate(double value)
- {
- return FPRecipEstimateFpscrImpl(value, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
- {
- return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
- }
-
- private static double FPRecipEstimateFpscrImpl(double value, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
-
- double result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- result = FPProcessNaN(type, op, context, fpcr);
- }
- else if (type == FPType.Infinity)
- {
- result = FPZero(sign);
- }
- else if (type == FPType.Zero)
- {
- result = FPInfinity(sign);
-
- SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
- }
- else if (Math.Abs(value) < Math.Pow(2d, -1024))
- {
- bool overflowToInf = fpcr.GetRoundingMode() switch
- {
- FPRoundingMode.ToNearest => true,
- FPRoundingMode.TowardsPlusInfinity => !sign,
- FPRoundingMode.TowardsMinusInfinity => sign,
- FPRoundingMode.TowardsZero => false,
- _ => throw new ArgumentException($"Invalid rounding mode \"{fpcr.GetRoundingMode()}\"."),
- };
- result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
-
- SoftFloat.FPProcessException(FPException.Overflow, context, fpcr);
- SoftFloat.FPProcessException(FPException.Inexact, context, fpcr);
- }
- else if ((fpcr & FPCR.Fz) != 0 && (Math.Abs(value) >= Math.Pow(2d, 1022)))
- {
- result = FPZero(sign);
-
- context.Fpsr |= FPSR.Ufc;
- }
- else
- {
- ulong fraction = op & 0x000FFFFFFFFFFFFFul;
- uint exp = (uint)((op & 0x7FF0000000000000ul) >> 52);
-
- if (exp == 0u)
- {
- if ((fraction & 0x0008000000000000ul) == 0ul)
- {
- fraction = (fraction & 0x0003FFFFFFFFFFFFul) << 2;
- exp -= 1u;
- }
- else
- {
- fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
- }
- }
-
- uint scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
-
- uint resultExp = 2045u - exp;
-
- uint estimate = (uint)SoftFloat.RecipEstimateTable[scaled - 256u] + 256u;
-
- fraction = (ulong)(estimate & 0xFFu) << 44;
-
- if (resultExp == 0u)
- {
- fraction = ((fraction & 0x000FFFFFFFFFFFFEul) | 0x0010000000000000ul) >> 1;
- }
- else if (resultExp + 1u == 0u)
- {
- fraction = ((fraction & 0x000FFFFFFFFFFFFCul) | 0x0010000000000000ul) >> 2;
- resultExp = 0u;
- }
-
- result = BitConverter.Int64BitsToDouble(
- (long)((sign ? 1ul : 0ul) << 63 | (resultExp & 0x7FFul) << 52 | (fraction & 0x000FFFFFFFFFFFFFul)));
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPRecipStep(double value1, double value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.StandardFpcrValue;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- double product;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- product = FPZero(false);
- }
- else
- {
- product = FPMulFpscrImpl(value1, value2, true);
- }
-
- result = FPSubFpscr(FPTwo(false), product, true);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPRecipStepFused(double value1, double value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPNeg();
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- result = FPTwo(false);
- }
- else if (inf1 || inf2)
- {
- result = FPInfinity(sign1 ^ sign2);
- }
- else
- {
- result = Math.FusedMultiplyAdd(value1, value2, 2d);
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPRecpX(double value)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
-
- double result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- result = FPProcessNaN(type, op, context, fpcr);
- }
- else
- {
- ulong notExp = (~op >> 52) & 0x7FFul;
- ulong maxExp = 0x7FEul;
-
- result = BitConverter.Int64BitsToDouble(
- (long)((sign ? 1ul : 0ul) << 63 | (notExp == 0x7FFul ? maxExp : notExp) << 52));
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPRSqrtEstimate(double value)
- {
- return FPRSqrtEstimateFpscrImpl(value, false);
- }
-
- [UnmanagedCallersOnly]
- public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
- {
- return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
- }
-
- private static double FPRSqrtEstimateFpscrImpl(double value, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
-
- double result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- result = FPProcessNaN(type, op, context, fpcr);
- }
- else if (type == FPType.Zero)
- {
- result = FPInfinity(sign);
-
- SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
- }
- else if (sign)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if (type == FPType.Infinity)
- {
- result = FPZero(false);
- }
- else
- {
- ulong fraction = op & 0x000FFFFFFFFFFFFFul;
- uint exp = (uint)((op & 0x7FF0000000000000ul) >> 52);
-
- if (exp == 0u)
- {
- while ((fraction & 0x0008000000000000ul) == 0ul)
- {
- fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
- exp -= 1u;
- }
-
- fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
- }
-
- uint scaled;
-
- if ((exp & 1u) == 0u)
- {
- scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
- }
- else
- {
- scaled = (uint)(((fraction & 0x000FE00000000000ul) | 0x0010000000000000ul) >> 45);
- }
-
- uint resultExp = (3068u - exp) >> 1;
-
- uint estimate = (uint)SoftFloat.RecipSqrtEstimateTable[scaled - 128u] + 256u;
-
- result = BitConverter.Int64BitsToDouble((long)((resultExp & 0x7FFul) << 52 | (estimate & 0xFFul) << 44));
- }
-
- return result;
- }
-
- public static double FPHalvedSub(double value1, double value2, ExecutionContext context, FPCR fpcr)
- {
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if (inf1 && inf2 && sign1 == sign2)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if ((inf1 && !sign1) || (inf2 && sign2))
- {
- result = FPInfinity(false);
- }
- else if ((inf1 && sign1) || (inf2 && !sign2))
- {
- result = FPInfinity(true);
- }
- else if (zero1 && zero2 && sign1 == !sign2)
- {
- result = FPZero(sign1);
- }
- else
- {
- result = (value1 - value2) / 2.0;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPRSqrtStep(double value1, double value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.StandardFpcrValue;
-
- value1 = value1.FPUnpack(out FPType type1, out _, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out _, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- double product;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- product = FPZero(false);
- }
- else
- {
- product = FPMulFpscrImpl(value1, value2, true);
- }
-
- result = FPHalvedSub(FPThree(false), product, context, fpcr);
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPRSqrtStepFused(double value1, double value2)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value1 = value1.FPNeg();
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if ((inf1 && zero2) || (zero1 && inf2))
- {
- result = FPOnePointFive(false);
- }
- else if (inf1 || inf2)
- {
- result = FPInfinity(sign1 ^ sign2);
- }
- else
- {
- result = Math.FusedMultiplyAdd(value1, value2, 3d) / 2d;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPSqrt(double value)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = context.Fpcr;
-
- value = value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
-
- double result;
-
- if (type is FPType.SNaN or FPType.QNaN)
- {
- result = FPProcessNaN(type, op, context, fpcr);
- }
- else if (type == FPType.Zero)
- {
- result = FPZero(sign);
- }
- else if (type == FPType.Infinity && !sign)
- {
- result = FPInfinity(sign);
- }
- else if (sign)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else
- {
- result = Math.Sqrt(value);
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
-
- return result;
- }
-
- [UnmanagedCallersOnly]
- public static double FPSub(double value1, double value2)
- {
- return FPSubFpscr(value1, value2, false);
- }
-
- public static double FPSubFpscr(double value1, double value2, bool standardFpscr)
- {
- ExecutionContext context = NativeInterface.GetContext();
- FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
-
- value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
- value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
-
- double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
-
- if (!done)
- {
- bool inf1 = type1 == FPType.Infinity;
- bool zero1 = type1 == FPType.Zero;
- bool inf2 = type2 == FPType.Infinity;
- bool zero2 = type2 == FPType.Zero;
-
- if (inf1 && inf2 && sign1 == sign2)
- {
- result = FPDefaultNaN();
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
- else if ((inf1 && !sign1) || (inf2 && sign2))
- {
- result = FPInfinity(false);
- }
- else if ((inf1 && sign1) || (inf2 && !sign2))
- {
- result = FPInfinity(true);
- }
- else if (zero1 && zero2 && sign1 == !sign2)
- {
- result = FPZero(sign1);
- }
- else
- {
- result = value1 - value2;
-
- if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
- {
- context.Fpsr |= FPSR.Ufc;
-
- result = FPZero(result < 0d);
- }
- }
- }
-
- return result;
- }
-
- public static double FPDefaultNaN()
- {
- return BitConverter.Int64BitsToDouble(0x7ff8000000000000);
- }
-
- public static double FPInfinity(bool sign)
- {
- return sign ? double.NegativeInfinity : double.PositiveInfinity;
- }
-
- public static double FPZero(bool sign)
- {
- return sign ? -0d : +0d;
- }
-
- public static double FPMaxNormal(bool sign)
- {
- return sign ? double.MinValue : double.MaxValue;
- }
-
- private static double FPTwo(bool sign)
- {
- return sign ? -2d : +2d;
- }
-
- private static double FPThree(bool sign)
- {
- return sign ? -3d : +3d;
- }
-
- private static double FPOnePointFive(bool sign)
- {
- return sign ? -1.5d : +1.5d;
- }
-
- private static double FPNeg(this double value)
- {
- return -value;
- }
-
- private static double ZerosOrOnes(bool ones)
- {
- return BitConverter.Int64BitsToDouble(ones ? -1L : 0L);
- }
-
- private static double FPUnpack(
- this double value,
- out FPType type,
- out bool sign,
- out ulong valueBits,
- ExecutionContext context,
- FPCR fpcr)
- {
- valueBits = (ulong)BitConverter.DoubleToInt64Bits(value);
-
- sign = (~valueBits & 0x8000000000000000ul) == 0ul;
-
- if ((valueBits & 0x7FF0000000000000ul) == 0ul)
- {
- if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul || (fpcr & FPCR.Fz) != 0)
- {
- type = FPType.Zero;
- value = FPZero(sign);
-
- if ((valueBits & 0x000FFFFFFFFFFFFFul) != 0ul)
- {
- SoftFloat.FPProcessException(FPException.InputDenorm, context, fpcr);
- }
- }
- else
- {
- type = FPType.Nonzero;
- }
- }
- else if ((~valueBits & 0x7FF0000000000000ul) == 0ul)
- {
- if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul)
- {
- type = FPType.Infinity;
- }
- else
- {
- type = (~valueBits & 0x0008000000000000ul) == 0ul ? FPType.QNaN : FPType.SNaN;
- value = FPZero(sign);
- }
- }
- else
- {
- type = FPType.Nonzero;
- }
-
- return value;
- }
-
- private static double FPProcessNaNs(
- FPType type1,
- FPType type2,
- ulong op1,
- ulong op2,
- out bool done,
- ExecutionContext context,
- FPCR fpcr)
- {
- done = true;
-
- if (type1 == FPType.SNaN)
- {
- return FPProcessNaN(type1, op1, context, fpcr);
- }
- else if (type2 == FPType.SNaN)
- {
- return FPProcessNaN(type2, op2, context, fpcr);
- }
- else if (type1 == FPType.QNaN)
- {
- return FPProcessNaN(type1, op1, context, fpcr);
- }
- else if (type2 == FPType.QNaN)
- {
- return FPProcessNaN(type2, op2, context, fpcr);
- }
-
- done = false;
-
- return FPZero(false);
- }
-
- private static double FPProcessNaNs3(
- FPType type1,
- FPType type2,
- FPType type3,
- ulong op1,
- ulong op2,
- ulong op3,
- out bool done,
- ExecutionContext context,
- FPCR fpcr)
- {
- done = true;
-
- if (type1 == FPType.SNaN)
- {
- return FPProcessNaN(type1, op1, context, fpcr);
- }
- else if (type2 == FPType.SNaN)
- {
- return FPProcessNaN(type2, op2, context, fpcr);
- }
- else if (type3 == FPType.SNaN)
- {
- return FPProcessNaN(type3, op3, context, fpcr);
- }
- else if (type1 == FPType.QNaN)
- {
- return FPProcessNaN(type1, op1, context, fpcr);
- }
- else if (type2 == FPType.QNaN)
- {
- return FPProcessNaN(type2, op2, context, fpcr);
- }
- else if (type3 == FPType.QNaN)
- {
- return FPProcessNaN(type3, op3, context, fpcr);
- }
-
- done = false;
-
- return FPZero(false);
- }
-
- private static double FPProcessNaN(FPType type, ulong op, ExecutionContext context, FPCR fpcr)
- {
- if (type == FPType.SNaN)
- {
- op |= 1ul << 51;
-
- SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
- }
-
- if ((fpcr & FPCR.Dn) != 0)
- {
- return FPDefaultNaN();
- }
-
- return BitConverter.Int64BitsToDouble((long)op);
- }
- }
-}
diff --git a/src/ARMeilleure/Instructions/SoftFloat/SoftFloat.cs b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat.cs
new file mode 100644
index 000000000..366dd543e
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat.cs
@@ -0,0 +1,111 @@
+using ARMeilleure.State;
+using System;
+using System.Diagnostics;
+
+namespace ARMeilleure.Instructions
+{
+ static class SoftFloat
+ {
+ static SoftFloat()
+ {
+ RecipEstimateTable = BuildRecipEstimateTable();
+ RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
+ }
+
+ public static readonly byte[] RecipEstimateTable;
+ public static readonly byte[] RecipSqrtEstimateTable;
+
+ private static byte[] BuildRecipEstimateTable()
+ {
+ byte[] tbl = new byte[256];
+
+ for (int idx = 0; idx < 256; idx++)
+ {
+ uint src = (uint)idx + 256u;
+
+ Debug.Assert(src is >= 256u and < 512u);
+
+ src = (src << 1) + 1u;
+
+ uint aux = (1u << 19) / src;
+
+ uint dst = (aux + 1u) >> 1;
+
+ Debug.Assert(dst is >= 256u and < 512u);
+
+ tbl[idx] = (byte)(dst - 256u);
+ }
+
+ return tbl;
+ }
+
+ private static byte[] BuildRecipSqrtEstimateTable()
+ {
+ byte[] tbl = new byte[384];
+
+ for (int idx = 0; idx < 384; idx++)
+ {
+ uint src = (uint)idx + 128u;
+
+ Debug.Assert(src is >= 128u and < 512u);
+
+ if (src < 256u)
+ {
+ src = (src << 1) + 1u;
+ }
+ else
+ {
+ src = (src >> 1) << 1;
+ src = (src + 1u) << 1;
+ }
+
+ uint aux = 512u;
+
+ while (src * (aux + 1u) * (aux + 1u) < (1u << 28))
+ {
+ aux++;
+ }
+
+ uint dst = (aux + 1u) >> 1;
+
+ Debug.Assert(dst is >= 256u and < 512u);
+
+ tbl[idx] = (byte)(dst - 256u);
+ }
+
+ return tbl;
+ }
+
+ public static void FPProcessException(FPException exc, ExecutionContext context)
+ {
+ FPProcessException(exc, context, context.Fpcr);
+ }
+
+ public static void FPProcessException(FPException exc, ExecutionContext context, FPCR fpcr)
+ {
+ int enable = (int)exc + 8;
+
+ if ((fpcr & (FPCR)(1 << enable)) != 0)
+ {
+ throw new NotImplementedException("Floating-point trap handling.");
+ }
+ else
+ {
+ context.Fpsr |= (FPSR)(1 << (int)exc);
+ }
+ }
+
+ extension(FPCR fpcr)
+ {
+ public FPRoundingMode RoundingMode
+ {
+ get
+ {
+ const int RModeShift = 22;
+
+ return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u);
+ }
+ }
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFloat/SoftFloat16.cs b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat16.cs
new file mode 100644
index 000000000..4038aceb6
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat16.cs
@@ -0,0 +1,212 @@
+using ARMeilleure.State;
+using System;
+
+namespace ARMeilleure.Instructions
+{
+ static class SoftFloat16
+ {
+ public static ushort FPDefaultNaN()
+ {
+ return (ushort)0x7E00u;
+ }
+
+ public static ushort FPInfinity(bool sign)
+ {
+ return sign ? (ushort)0xFC00u : (ushort)0x7C00u;
+ }
+
+ public static ushort FPZero(bool sign)
+ {
+ return sign ? (ushort)0x8000u : (ushort)0x0000u;
+ }
+
+ public static ushort FPMaxNormal(bool sign)
+ {
+ return sign ? (ushort)0xFBFFu : (ushort)0x7BFFu;
+ }
+
+ public static double FPUnpackCv(
+ this ushort valueBits,
+ out FPType type,
+ out bool sign,
+ ExecutionContext context)
+ {
+ sign = (~(uint)valueBits & 0x8000u) == 0u;
+
+ uint exp16 = ((uint)valueBits & 0x7C00u) >> 10;
+ uint frac16 = (uint)valueBits & 0x03FFu;
+
+ double real;
+
+ if (exp16 == 0u)
+ {
+ if (frac16 == 0u)
+ {
+ type = FPType.Zero;
+ real = 0d;
+ }
+ else
+ {
+ type = FPType.Nonzero; // Subnormal.
+ real = Math.Pow(2d, -14) * ((double)frac16 * Math.Pow(2d, -10));
+ }
+ }
+ else if (exp16 == 0x1Fu && (context.Fpcr & FPCR.Ahp) == 0)
+ {
+ if (frac16 == 0u)
+ {
+ type = FPType.Infinity;
+ real = Math.Pow(2d, 1000);
+ }
+ else
+ {
+ type = (~frac16 & 0x0200u) == 0u ? FPType.QNaN : FPType.SNaN;
+ real = 0d;
+ }
+ }
+ else
+ {
+ type = FPType.Nonzero; // Normal.
+ real = Math.Pow(2d, (int)exp16 - 15) * (1d + (double)frac16 * Math.Pow(2d, -10));
+ }
+
+ return sign ? -real : real;
+ }
+
+ public static ushort FPRoundCv(double real, ExecutionContext context)
+ {
+ const int MinimumExp = -14;
+
+ const int E = 5;
+ const int F = 10;
+
+ bool sign;
+ double mantissa;
+
+ if (real < 0d)
+ {
+ sign = true;
+ mantissa = -real;
+ }
+ else
+ {
+ sign = false;
+ mantissa = real;
+ }
+
+ int exponent = 0;
+
+ while (mantissa < 1d)
+ {
+ mantissa *= 2d;
+ exponent--;
+ }
+
+ while (mantissa >= 2d)
+ {
+ mantissa /= 2d;
+ exponent++;
+ }
+
+ uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
+
+ if (biasedExp == 0u)
+ {
+ mantissa /= Math.Pow(2d, MinimumExp - exponent);
+ }
+
+ uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
+ double error = mantissa * Math.Pow(2d, F) - (double)intMant;
+
+ if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
+ {
+ SoftFloat.FPProcessException(FPException.Underflow, context);
+ }
+
+ bool overflowToInf;
+ bool roundUp;
+
+ switch (context.Fpcr.RoundingMode)
+ {
+ case FPRoundingMode.ToNearest:
+ roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
+ overflowToInf = true;
+ break;
+
+ case FPRoundingMode.TowardsPlusInfinity:
+ roundUp = (error != 0d && !sign);
+ overflowToInf = !sign;
+ break;
+
+ case FPRoundingMode.TowardsMinusInfinity:
+ roundUp = (error != 0d && sign);
+ overflowToInf = sign;
+ break;
+
+ case FPRoundingMode.TowardsZero:
+ roundUp = false;
+ overflowToInf = false;
+ break;
+
+ default:
+ throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
+ }
+
+ if (roundUp)
+ {
+ intMant++;
+
+ if (intMant == 1u << F)
+ {
+ biasedExp = 1u;
+ }
+
+ if (intMant == 1u << (F + 1))
+ {
+ biasedExp++;
+ intMant >>= 1;
+ }
+ }
+
+ ushort resultBits;
+
+ if ((context.Fpcr & FPCR.Ahp) == 0)
+ {
+ if (biasedExp >= (1u << E) - 1u)
+ {
+ resultBits = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
+
+ SoftFloat.FPProcessException(FPException.Overflow, context);
+
+ error = 1d;
+ }
+ else
+ {
+ resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
+ }
+ }
+ else
+ {
+ if (biasedExp >= 1u << E)
+ {
+ resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context);
+
+ error = 0d;
+ }
+ else
+ {
+ resultBits = (ushort)((sign ? 1u : 0u) << 15 | (biasedExp & 0x1Fu) << 10 | (intMant & 0x03FFu));
+ }
+ }
+
+ if (error != 0d)
+ {
+ SoftFloat.FPProcessException(FPException.Inexact, context);
+ }
+
+ return resultBits;
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_32.cs b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_32.cs
new file mode 100644
index 000000000..f2d0f1eb4
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_32.cs
@@ -0,0 +1,182 @@
+using ARMeilleure.State;
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static class SoftFloat16_32
+ {
+ [UnmanagedCallersOnly]
+ public static float FPConvert(ushort valueBits)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+
+ double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
+
+ float result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ if ((context.Fpcr & FPCR.Dn) != 0)
+ {
+ result = SoftFloat32.FPDefaultNaN();
+ }
+ else
+ {
+ result = FPConvertNaN(valueBits);
+ }
+
+ if (type == FPType.SNaN)
+ {
+ SoftFloat.FPProcessException(FPException.InvalidOp, context);
+ }
+ }
+ else if (type == FPType.Infinity)
+ {
+ result = SoftFloat32.FPInfinity(sign);
+ }
+ else if (type == FPType.Zero)
+ {
+ result = SoftFloat32.FPZero(sign);
+ }
+ else
+ {
+ result = FPRoundCv(real, context);
+ }
+
+ return result;
+ }
+
+ private static float FPRoundCv(double real, ExecutionContext context)
+ {
+ const int MinimumExp = -126;
+
+ const int E = 8;
+ const int F = 23;
+
+ bool sign;
+ double mantissa;
+
+ if (real < 0d)
+ {
+ sign = true;
+ mantissa = -real;
+ }
+ else
+ {
+ sign = false;
+ mantissa = real;
+ }
+
+ int exponent = 0;
+
+ while (mantissa < 1d)
+ {
+ mantissa *= 2d;
+ exponent--;
+ }
+
+ while (mantissa >= 2d)
+ {
+ mantissa /= 2d;
+ exponent++;
+ }
+
+ if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ return SoftFloat32.FPZero(sign);
+ }
+
+ uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
+
+ if (biasedExp == 0u)
+ {
+ mantissa /= Math.Pow(2d, MinimumExp - exponent);
+ }
+
+ uint intMant = (uint)Math.Floor(mantissa * Math.Pow(2d, F));
+ double error = mantissa * Math.Pow(2d, F) - (double)intMant;
+
+ if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
+ {
+ SoftFloat.FPProcessException(FPException.Underflow, context);
+ }
+
+ bool overflowToInf;
+ bool roundUp;
+
+ switch (context.Fpcr.RoundingMode)
+ {
+ case FPRoundingMode.ToNearest:
+ roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
+ overflowToInf = true;
+ break;
+
+ case FPRoundingMode.TowardsPlusInfinity:
+ roundUp = (error != 0d && !sign);
+ overflowToInf = !sign;
+ break;
+
+ case FPRoundingMode.TowardsMinusInfinity:
+ roundUp = (error != 0d && sign);
+ overflowToInf = sign;
+ break;
+
+ case FPRoundingMode.TowardsZero:
+ roundUp = false;
+ overflowToInf = false;
+ break;
+
+ default:
+ throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
+ }
+
+ if (roundUp)
+ {
+ intMant++;
+
+ if (intMant == 1u << F)
+ {
+ biasedExp = 1u;
+ }
+
+ if (intMant == 1u << (F + 1))
+ {
+ biasedExp++;
+ intMant >>= 1;
+ }
+ }
+
+ float result;
+
+ if (biasedExp >= (1u << E) - 1u)
+ {
+ result = overflowToInf ? SoftFloat32.FPInfinity(sign) : SoftFloat32.FPMaxNormal(sign);
+
+ SoftFloat.FPProcessException(FPException.Overflow, context);
+
+ error = 1d;
+ }
+ else
+ {
+ result = BitConverter.Int32BitsToSingle(
+ (int)((sign ? 1u : 0u) << 31 | (biasedExp & 0xFFu) << 23 | (intMant & 0x007FFFFFu)));
+ }
+
+ if (error != 0d)
+ {
+ SoftFloat.FPProcessException(FPException.Inexact, context);
+ }
+
+ return result;
+ }
+
+ private static float FPConvertNaN(ushort valueBits)
+ {
+ return BitConverter.Int32BitsToSingle(
+ (int)(((uint)valueBits & 0x8000u) << 16 | 0x7FC00000u | ((uint)valueBits & 0x01FFu) << 13));
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_64.cs b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_64.cs
new file mode 100644
index 000000000..5167c1908
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat16_64.cs
@@ -0,0 +1,182 @@
+using ARMeilleure.State;
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static class SoftFloat16_64
+ {
+ [UnmanagedCallersOnly]
+ public static double FPConvert(ushort valueBits)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+
+ double real = valueBits.FPUnpackCv(out FPType type, out bool sign, context);
+
+ double result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ if ((context.Fpcr & FPCR.Dn) != 0)
+ {
+ result = SoftFloat64.FPDefaultNaN();
+ }
+ else
+ {
+ result = FPConvertNaN(valueBits);
+ }
+
+ if (type == FPType.SNaN)
+ {
+ SoftFloat.FPProcessException(FPException.InvalidOp, context);
+ }
+ }
+ else if (type == FPType.Infinity)
+ {
+ result = SoftFloat64.FPInfinity(sign);
+ }
+ else if (type == FPType.Zero)
+ {
+ result = SoftFloat64.FPZero(sign);
+ }
+ else
+ {
+ result = FPRoundCv(real, context);
+ }
+
+ return result;
+ }
+
+ private static double FPRoundCv(double real, ExecutionContext context)
+ {
+ const int MinimumExp = -1022;
+
+ const int E = 11;
+ const int F = 52;
+
+ bool sign;
+ double mantissa;
+
+ if (real < 0d)
+ {
+ sign = true;
+ mantissa = -real;
+ }
+ else
+ {
+ sign = false;
+ mantissa = real;
+ }
+
+ int exponent = 0;
+
+ while (mantissa < 1d)
+ {
+ mantissa *= 2d;
+ exponent--;
+ }
+
+ while (mantissa >= 2d)
+ {
+ mantissa /= 2d;
+ exponent++;
+ }
+
+ if ((context.Fpcr & FPCR.Fz) != 0 && exponent < MinimumExp)
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ return SoftFloat64.FPZero(sign);
+ }
+
+ uint biasedExp = (uint)Math.Max(exponent - MinimumExp + 1, 0);
+
+ if (biasedExp == 0u)
+ {
+ mantissa /= Math.Pow(2d, MinimumExp - exponent);
+ }
+
+ ulong intMant = (ulong)Math.Floor(mantissa * Math.Pow(2d, F));
+ double error = mantissa * Math.Pow(2d, F) - (double)intMant;
+
+ if (biasedExp == 0u && (error != 0d || (context.Fpcr & FPCR.Ufe) != 0))
+ {
+ SoftFloat.FPProcessException(FPException.Underflow, context);
+ }
+
+ bool overflowToInf;
+ bool roundUp;
+
+ switch (context.Fpcr.RoundingMode)
+ {
+ case FPRoundingMode.ToNearest:
+ roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
+ overflowToInf = true;
+ break;
+
+ case FPRoundingMode.TowardsPlusInfinity:
+ roundUp = (error != 0d && !sign);
+ overflowToInf = !sign;
+ break;
+
+ case FPRoundingMode.TowardsMinusInfinity:
+ roundUp = (error != 0d && sign);
+ overflowToInf = sign;
+ break;
+
+ case FPRoundingMode.TowardsZero:
+ roundUp = false;
+ overflowToInf = false;
+ break;
+
+ default:
+ throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.RoundingMode}\".");
+ }
+
+ if (roundUp)
+ {
+ intMant++;
+
+ if (intMant == 1ul << F)
+ {
+ biasedExp = 1u;
+ }
+
+ if (intMant == 1ul << (F + 1))
+ {
+ biasedExp++;
+ intMant >>= 1;
+ }
+ }
+
+ double result;
+
+ if (biasedExp >= (1u << E) - 1u)
+ {
+ result = overflowToInf ? SoftFloat64.FPInfinity(sign) : SoftFloat64.FPMaxNormal(sign);
+
+ SoftFloat.FPProcessException(FPException.Overflow, context);
+
+ error = 1d;
+ }
+ else
+ {
+ result = BitConverter.Int64BitsToDouble(
+ (long)((sign ? 1ul : 0ul) << 63 | (biasedExp & 0x7FFul) << 52 | (intMant & 0x000FFFFFFFFFFFFFul)));
+ }
+
+ if (error != 0d)
+ {
+ SoftFloat.FPProcessException(FPException.Inexact, context);
+ }
+
+ return result;
+ }
+
+ private static double FPConvertNaN(ushort valueBits)
+ {
+ return BitConverter.Int64BitsToDouble(
+ (long)(((ulong)valueBits & 0x8000ul) << 48 | 0x7FF8000000000000ul | ((ulong)valueBits & 0x01FFul) << 42));
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFloat/SoftFloat32.cs b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat32.cs
new file mode 100644
index 000000000..a7ab054be
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat32.cs
@@ -0,0 +1,1421 @@
+using ARMeilleure.State;
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+static class SoftFloat32
+ {
+ [UnmanagedCallersOnly]
+ public static float FPAdd(float value1, float value2)
+ {
+ return FPAddFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static float FPAddFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if (inf1 && inf2 && sign1 == !sign2)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((inf1 && !sign1) || (inf2 && !sign2))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((inf1 && sign1) || (inf2 && sign2))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zero1 && zero2 && sign1 == sign2)
+ {
+ result = FPZero(sign1);
+ }
+ else
+ {
+ result = value1 + value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static int FPCompare(float value1, float value2, byte signalNaNs)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ int result;
+
+ if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
+ {
+ result = 0b0011;
+
+ if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs == 1)
+ {
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ }
+ else
+ {
+ if (value1 == value2)
+ {
+ result = 0b0110;
+ }
+ else if (value1 < value2)
+ {
+ result = 0b1000;
+ }
+ else
+ {
+ result = 0b0010;
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareEQ(float value1, float value2)
+ {
+ return FPCompareEQFpscrImpl(value1, value2, false);
+ }
+
+ private static float FPCompareEQFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ float result;
+
+ if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
+ {
+ result = ZerosOrOnes(false);
+
+ if (type1 == FPType.SNaN || type2 == FPType.SNaN)
+ {
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ }
+ else
+ {
+ result = ZerosOrOnes(value1 == value2);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareGE(float value1, float value2)
+ {
+ return FPCompareGEFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static float FPCompareGEFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ float result;
+
+ if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
+ {
+ result = ZerosOrOnes(false);
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else
+ {
+ result = ZerosOrOnes(value1 >= value2);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareGT(float value1, float value2)
+ {
+ return FPCompareGTFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static float FPCompareGTFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ float result;
+
+ if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
+ {
+ result = ZerosOrOnes(false);
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else
+ {
+ result = ZerosOrOnes(value1 > value2);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareLE(float value1, float value2)
+ {
+ return FPCompareGEFpscrImpl(value2, value1, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareLT(float value1, float value2)
+ {
+ return FPCompareGTFpscrImpl(value2, value1, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPDiv(float value1, float value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && inf2) || (zero1 && zero2))
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if (inf1 || zero2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+
+ if (!inf1)
+ {
+ SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
+ }
+ }
+ else if (zero1 || inf2)
+ {
+ result = FPZero(sign1 ^ sign2);
+ }
+ else
+ {
+ result = value1 / value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMax(float value1, float value2)
+ {
+ return FPMaxFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static float FPMaxFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ if (value1 > value2)
+ {
+ if (type1 == FPType.Infinity)
+ {
+ result = FPInfinity(sign1);
+ }
+ else if (type1 == FPType.Zero)
+ {
+ result = FPZero(sign1 && sign2);
+ }
+ else
+ {
+ result = value1;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+ else
+ {
+ if (type2 == FPType.Infinity)
+ {
+ result = FPInfinity(sign2);
+ }
+ else if (type2 == FPType.Zero)
+ {
+ result = FPZero(sign1 && sign2);
+ }
+ else
+ {
+ result = value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMaxNum(float value1, float value2)
+ {
+ return FPMaxNumFpscrImpl(value1, value2, false);
+ }
+
+ private static float FPMaxNumFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ if (type1 == FPType.QNaN && type2 != FPType.QNaN)
+ {
+ value1 = FPInfinity(true);
+ }
+ else if (type1 != FPType.QNaN && type2 == FPType.QNaN)
+ {
+ value2 = FPInfinity(true);
+ }
+
+ return FPMaxFpscrImpl(value1, value2, standardFpscr);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMin(float value1, float value2)
+ {
+ return FPMinFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static float FPMinFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ if (value1 < value2)
+ {
+ if (type1 == FPType.Infinity)
+ {
+ result = FPInfinity(sign1);
+ }
+ else if (type1 == FPType.Zero)
+ {
+ result = FPZero(sign1 || sign2);
+ }
+ else
+ {
+ result = value1;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+ else
+ {
+ if (type2 == FPType.Infinity)
+ {
+ result = FPInfinity(sign2);
+ }
+ else if (type2 == FPType.Zero)
+ {
+ result = FPZero(sign1 || sign2);
+ }
+ else
+ {
+ result = value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMinNum(float value1, float value2)
+ {
+ return FPMinNumFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static float FPMinNumFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ if (type1 == FPType.QNaN && type2 != FPType.QNaN)
+ {
+ value1 = FPInfinity(false);
+ }
+ else if (type1 != FPType.QNaN && type2 == FPType.QNaN)
+ {
+ value2 = FPInfinity(false);
+ }
+
+ return FPMinFpscrImpl(value1, value2, standardFpscr);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMul(float value1, float value2)
+ {
+ return FPMulFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
+ {
+ return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static float FPMulFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if (inf1 || inf2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+ }
+ else if (zero1 || zero2)
+ {
+ result = FPZero(sign1 ^ sign2);
+ }
+ else
+ {
+ result = value1 * value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMulAdd(float valueA, float value1, float value2)
+ {
+ return FPMulAddFpscrImpl(valueA, value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
+ {
+ return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
+ }
+
+ private static float FPMulAddFpscrImpl(float valueA, float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ valueA = valueA.FPUnpack(out FPType typeA, out bool signA, out uint addend, context, fpcr);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ float result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, context, fpcr);
+
+ if (typeA == FPType.QNaN && ((inf1 && zero2) || (zero1 && inf2)))
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+
+ if (!done)
+ {
+ bool infA = typeA == FPType.Infinity;
+ bool zeroA = typeA == FPType.Zero;
+
+ bool signP = sign1 ^ sign2;
+ bool infP = inf1 || inf2;
+ bool zeroP = zero1 || zero2;
+
+ if ((inf1 && zero2) || (zero1 && inf2) || (infA && infP && signA != signP))
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((infA && !signA) || (infP && !signP))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((infA && signA) || (infP && signP))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zeroA && zeroP && signA == signP)
+ {
+ result = FPZero(signA);
+ }
+ else
+ {
+ result = MathF.FusedMultiplyAdd(value1, value2, valueA);
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMulSub(float valueA, float value1, float value2)
+ {
+ value1 = value1.FPNeg();
+
+ return FPMulAddFpscrImpl(valueA, value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
+ {
+ value1 = value1.FPNeg();
+
+ return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPMulX(float value1, float value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ result = FPTwo(sign1 ^ sign2);
+ }
+ else if (inf1 || inf2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+ }
+ else if (zero1 || zero2)
+ {
+ result = FPZero(sign1 ^ sign2);
+ }
+ else
+ {
+ result = value1 * value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPNegMulAdd(float valueA, float value1, float value2)
+ {
+ valueA = valueA.FPNeg();
+ value1 = value1.FPNeg();
+
+ return FPMulAddFpscrImpl(valueA, value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPNegMulSub(float valueA, float value1, float value2)
+ {
+ valueA = valueA.FPNeg();
+
+ return FPMulAddFpscrImpl(valueA, value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPRecipEstimate(float value)
+ {
+ return FPRecipEstimateFpscrImpl(value, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
+ {
+ return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
+ }
+
+ private static float FPRecipEstimateFpscrImpl(float value, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
+
+ float result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ result = FPProcessNaN(type, op, context, fpcr);
+ }
+ else if (type == FPType.Infinity)
+ {
+ result = FPZero(sign);
+ }
+ else if (type == FPType.Zero)
+ {
+ result = FPInfinity(sign);
+
+ SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
+ }
+ else if (MathF.Abs(value) < MathF.Pow(2f, -128))
+ {
+ bool overflowToInf = fpcr.RoundingMode switch
+ {
+ FPRoundingMode.ToNearest => true,
+ FPRoundingMode.TowardsPlusInfinity => !sign,
+ FPRoundingMode.TowardsMinusInfinity => sign,
+ FPRoundingMode.TowardsZero => false,
+ _ => throw new ArgumentException($"Invalid rounding mode \"{fpcr.RoundingMode}\"."),
+ };
+ result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
+
+ SoftFloat.FPProcessException(FPException.Overflow, context, fpcr);
+ SoftFloat.FPProcessException(FPException.Inexact, context, fpcr);
+ }
+ else if ((fpcr & FPCR.Fz) != 0 && (MathF.Abs(value) >= MathF.Pow(2f, 126)))
+ {
+ result = FPZero(sign);
+
+ context.Fpsr |= FPSR.Ufc;
+ }
+ else
+ {
+ ulong fraction = (ulong)(op & 0x007FFFFFu) << 29;
+ uint exp = (op & 0x7F800000u) >> 23;
+
+ if (exp == 0u)
+ {
+ if ((fraction & 0x0008000000000000ul) == 0ul)
+ {
+ fraction = (fraction & 0x0003FFFFFFFFFFFFul) << 2;
+ exp -= 1u;
+ }
+ else
+ {
+ fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
+ }
+ }
+
+ uint scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
+
+ uint resultExp = 253u - exp;
+
+ uint estimate = (uint)SoftFloat.RecipEstimateTable[scaled - 256u] + 256u;
+
+ fraction = (ulong)(estimate & 0xFFu) << 44;
+
+ if (resultExp == 0u)
+ {
+ fraction = ((fraction & 0x000FFFFFFFFFFFFEul) | 0x0010000000000000ul) >> 1;
+ }
+ else if (resultExp + 1u == 0u)
+ {
+ fraction = ((fraction & 0x000FFFFFFFFFFFFCul) | 0x0010000000000000ul) >> 2;
+ resultExp = 0u;
+ }
+
+ result = BitConverter.Int32BitsToSingle(
+ (int)((sign ? 1u : 0u) << 31 | (resultExp & 0xFFu) << 23 | (uint)(fraction >> 29) & 0x007FFFFFu));
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPRecipStep(float value1, float value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.StandardFpcrValue;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ float product;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ product = FPZero(false);
+ }
+ else
+ {
+ product = FPMulFpscrImpl(value1, value2, true);
+ }
+
+ result = FPSubFpscrImpl(FPTwo(false), product, true);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPRecipStepFused(float value1, float value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPNeg();
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ result = FPTwo(false);
+ }
+ else if (inf1 || inf2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+ }
+ else
+ {
+ result = MathF.FusedMultiplyAdd(value1, value2, 2f);
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPRecpX(float value)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
+
+ float result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ result = FPProcessNaN(type, op, context, fpcr);
+ }
+ else
+ {
+ uint notExp = (~op >> 23) & 0xFFu;
+ uint maxExp = 0xFEu;
+
+ result = BitConverter.Int32BitsToSingle(
+ (int)((sign ? 1u : 0u) << 31 | (notExp == 0xFFu ? maxExp : notExp) << 23));
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPRSqrtEstimate(float value)
+ {
+ return FPRSqrtEstimateFpscrImpl(value, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
+ {
+ return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
+ }
+
+ private static float FPRSqrtEstimateFpscrImpl(float value, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
+
+ float result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ result = FPProcessNaN(type, op, context, fpcr);
+ }
+ else if (type == FPType.Zero)
+ {
+ result = FPInfinity(sign);
+
+ SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
+ }
+ else if (sign)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if (type == FPType.Infinity)
+ {
+ result = FPZero(false);
+ }
+ else
+ {
+ ulong fraction = (ulong)(op & 0x007FFFFFu) << 29;
+ uint exp = (op & 0x7F800000u) >> 23;
+
+ if (exp == 0u)
+ {
+ while ((fraction & 0x0008000000000000ul) == 0ul)
+ {
+ fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
+ exp -= 1u;
+ }
+
+ fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
+ }
+
+ uint scaled;
+
+ if ((exp & 1u) == 0u)
+ {
+ scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
+ }
+ else
+ {
+ scaled = (uint)(((fraction & 0x000FE00000000000ul) | 0x0010000000000000ul) >> 45);
+ }
+
+ uint resultExp = (380u - exp) >> 1;
+
+ uint estimate = (uint)SoftFloat.RecipSqrtEstimateTable[scaled - 128u] + 256u;
+
+ result = BitConverter.Int32BitsToSingle((int)((resultExp & 0xFFu) << 23 | (estimate & 0xFFu) << 15));
+ }
+
+ return result;
+ }
+
+ public static float FPHalvedSub(float value1, float value2, ExecutionContext context, FPCR fpcr)
+ {
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if (inf1 && inf2 && sign1 == sign2)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((inf1 && !sign1) || (inf2 && sign2))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((inf1 && sign1) || (inf2 && !sign2))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zero1 && zero2 && sign1 == !sign2)
+ {
+ result = FPZero(sign1);
+ }
+ else
+ {
+ result = (value1 - value2) / 2.0f;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPRSqrtStep(float value1, float value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.StandardFpcrValue;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ float product;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ product = FPZero(false);
+ }
+ else
+ {
+ product = FPMulFpscrImpl(value1, value2, true);
+ }
+
+ result = FPHalvedSub(FPThree(false), product, context, fpcr);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPRSqrtStepFused(float value1, float value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPNeg();
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ result = FPOnePointFive(false);
+ }
+ else if (inf1 || inf2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+ }
+ else
+ {
+ result = MathF.FusedMultiplyAdd(value1, value2, 3f) / 2f;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPSqrt(float value)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value = value.FPUnpack(out FPType type, out bool sign, out uint op, context, fpcr);
+
+ float result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ result = FPProcessNaN(type, op, context, fpcr);
+ }
+ else if (type == FPType.Zero)
+ {
+ result = FPZero(sign);
+ }
+ else if (type == FPType.Infinity && !sign)
+ {
+ result = FPInfinity(sign);
+ }
+ else if (sign)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else
+ {
+ result = MathF.Sqrt(value);
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static float FPSub(float value1, float value2)
+ {
+ return FPSubFpscrImpl(value1, value2, false);
+ }
+
+ private static float FPSubFpscrImpl(float value1, float value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out uint op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out uint op2, context, fpcr);
+
+ float result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if (inf1 && inf2 && sign1 == sign2)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((inf1 && !sign1) || (inf2 && sign2))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((inf1 && sign1) || (inf2 && !sign2))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zero1 && zero2 && sign1 == !sign2)
+ {
+ result = FPZero(sign1);
+ }
+ else
+ {
+ result = value1 - value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public static float FPDefaultNaN()
+ {
+ return BitConverter.Int32BitsToSingle(0x7fc00000);
+ }
+
+ public static float FPInfinity(bool sign)
+ {
+ return sign ? float.NegativeInfinity : float.PositiveInfinity;
+ }
+
+ public static float FPZero(bool sign)
+ {
+ return sign ? -0f : +0f;
+ }
+
+ public static float FPMaxNormal(bool sign)
+ {
+ return sign ? float.MinValue : float.MaxValue;
+ }
+
+ private static float FPTwo(bool sign)
+ {
+ return sign ? -2f : +2f;
+ }
+
+ private static float FPThree(bool sign)
+ {
+ return sign ? -3f : +3f;
+ }
+
+ private static float FPOnePointFive(bool sign)
+ {
+ return sign ? -1.5f : +1.5f;
+ }
+
+ private static float FPNeg(this float value)
+ {
+ return -value;
+ }
+
+ private static float ZerosOrOnes(bool ones)
+ {
+ return BitConverter.Int32BitsToSingle(ones ? -1 : 0);
+ }
+
+ private static float FPUnpack(
+ this float value,
+ out FPType type,
+ out bool sign,
+ out uint valueBits,
+ ExecutionContext context,
+ FPCR fpcr)
+ {
+ valueBits = (uint)BitConverter.SingleToInt32Bits(value);
+
+ sign = (~valueBits & 0x80000000u) == 0u;
+
+ if ((valueBits & 0x7F800000u) == 0u)
+ {
+ if ((valueBits & 0x007FFFFFu) == 0u || (fpcr & FPCR.Fz) != 0)
+ {
+ type = FPType.Zero;
+ value = FPZero(sign);
+
+ if ((valueBits & 0x007FFFFFu) != 0u)
+ {
+ SoftFloat.FPProcessException(FPException.InputDenorm, context, fpcr);
+ }
+ }
+ else
+ {
+ type = FPType.Nonzero;
+ }
+ }
+ else if ((~valueBits & 0x7F800000u) == 0u)
+ {
+ if ((valueBits & 0x007FFFFFu) == 0u)
+ {
+ type = FPType.Infinity;
+ }
+ else
+ {
+ type = (~valueBits & 0x00400000u) == 0u ? FPType.QNaN : FPType.SNaN;
+ value = FPZero(sign);
+ }
+ }
+ else
+ {
+ type = FPType.Nonzero;
+ }
+
+ return value;
+ }
+
+ private static float FPProcessNaNs(
+ FPType type1,
+ FPType type2,
+ uint op1,
+ uint op2,
+ out bool done,
+ ExecutionContext context,
+ FPCR fpcr)
+ {
+ done = true;
+
+ if (type1 == FPType.SNaN)
+ {
+ return FPProcessNaN(type1, op1, context, fpcr);
+ }
+ else if (type2 == FPType.SNaN)
+ {
+ return FPProcessNaN(type2, op2, context, fpcr);
+ }
+ else if (type1 == FPType.QNaN)
+ {
+ return FPProcessNaN(type1, op1, context, fpcr);
+ }
+ else if (type2 == FPType.QNaN)
+ {
+ return FPProcessNaN(type2, op2, context, fpcr);
+ }
+
+ done = false;
+
+ return FPZero(false);
+ }
+
+ private static float FPProcessNaNs3(
+ FPType type1,
+ FPType type2,
+ FPType type3,
+ uint op1,
+ uint op2,
+ uint op3,
+ out bool done,
+ ExecutionContext context,
+ FPCR fpcr)
+ {
+ done = true;
+
+ if (type1 == FPType.SNaN)
+ {
+ return FPProcessNaN(type1, op1, context, fpcr);
+ }
+ else if (type2 == FPType.SNaN)
+ {
+ return FPProcessNaN(type2, op2, context, fpcr);
+ }
+ else if (type3 == FPType.SNaN)
+ {
+ return FPProcessNaN(type3, op3, context, fpcr);
+ }
+ else if (type1 == FPType.QNaN)
+ {
+ return FPProcessNaN(type1, op1, context, fpcr);
+ }
+ else if (type2 == FPType.QNaN)
+ {
+ return FPProcessNaN(type2, op2, context, fpcr);
+ }
+ else if (type3 == FPType.QNaN)
+ {
+ return FPProcessNaN(type3, op3, context, fpcr);
+ }
+
+ done = false;
+
+ return FPZero(false);
+ }
+
+ private static float FPProcessNaN(FPType type, uint op, ExecutionContext context, FPCR fpcr)
+ {
+ if (type == FPType.SNaN)
+ {
+ op |= 1u << 22;
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+
+ if ((fpcr & FPCR.Dn) != 0)
+ {
+ return FPDefaultNaN();
+ }
+
+ return BitConverter.Int32BitsToSingle((int)op);
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFloat/SoftFloat32_16.cs b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat32_16.cs
new file mode 100644
index 000000000..67bc5149d
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat32_16.cs
@@ -0,0 +1,126 @@
+using ARMeilleure.State;
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static class SoftFloat32_16
+ {
+ [UnmanagedCallersOnly]
+ public static ushort FPConvert(float value)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+
+ double real = value.FPUnpackCv(out FPType type, out bool sign, out uint valueBits, context);
+
+ bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
+
+ ushort resultBits;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ if (altHp)
+ {
+ resultBits = SoftFloat16.FPZero(sign);
+ }
+ else if ((context.Fpcr & FPCR.Dn) != 0)
+ {
+ resultBits = SoftFloat16.FPDefaultNaN();
+ }
+ else
+ {
+ resultBits = FPConvertNaN(valueBits);
+ }
+
+ if (type == FPType.SNaN || altHp)
+ {
+ SoftFloat.FPProcessException(FPException.InvalidOp, context);
+ }
+ }
+ else if (type == FPType.Infinity)
+ {
+ if (altHp)
+ {
+ resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context);
+ }
+ else
+ {
+ resultBits = SoftFloat16.FPInfinity(sign);
+ }
+ }
+ else if (type == FPType.Zero)
+ {
+ resultBits = SoftFloat16.FPZero(sign);
+ }
+ else
+ {
+ resultBits = SoftFloat16.FPRoundCv(real, context);
+ }
+
+ return resultBits;
+ }
+
+ private static double FPUnpackCv(
+ this float value,
+ out FPType type,
+ out bool sign,
+ out uint valueBits,
+ ExecutionContext context)
+ {
+ valueBits = (uint)BitConverter.SingleToInt32Bits(value);
+
+ sign = (~valueBits & 0x80000000u) == 0u;
+
+ uint exp32 = (valueBits & 0x7F800000u) >> 23;
+ uint frac32 = valueBits & 0x007FFFFFu;
+
+ double real;
+
+ if (exp32 == 0u)
+ {
+ if (frac32 == 0u || (context.Fpcr & FPCR.Fz) != 0)
+ {
+ type = FPType.Zero;
+ real = 0d;
+
+ if (frac32 != 0u)
+ {
+ SoftFloat.FPProcessException(FPException.InputDenorm, context);
+ }
+ }
+ else
+ {
+ type = FPType.Nonzero; // Subnormal.
+ real = Math.Pow(2d, -126) * ((double)frac32 * Math.Pow(2d, -23));
+ }
+ }
+ else if (exp32 == 0xFFu)
+ {
+ if (frac32 == 0u)
+ {
+ type = FPType.Infinity;
+ real = Math.Pow(2d, 1000);
+ }
+ else
+ {
+ type = (~frac32 & 0x00400000u) == 0u ? FPType.QNaN : FPType.SNaN;
+ real = 0d;
+ }
+ }
+ else
+ {
+ type = FPType.Nonzero; // Normal.
+ real = Math.Pow(2d, (int)exp32 - 127) * (1d + (double)frac32 * Math.Pow(2d, -23));
+ }
+
+ return sign ? -real : real;
+ }
+
+ private static ushort FPConvertNaN(uint valueBits)
+ {
+ return (ushort)((valueBits & 0x80000000u) >> 16 | 0x7E00u | (valueBits & 0x003FE000u) >> 13);
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFloat/SoftFloat64.cs b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat64.cs
new file mode 100644
index 000000000..cad132e3a
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat64.cs
@@ -0,0 +1,1421 @@
+using ARMeilleure.State;
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static class SoftFloat64
+ {
+ [UnmanagedCallersOnly]
+ public static double FPAdd(double value1, double value2)
+ {
+ return FPAddFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPAddFpscrImpl(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if (inf1 && inf2 && sign1 == !sign2)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((inf1 && !sign1) || (inf2 && !sign2))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((inf1 && sign1) || (inf2 && sign2))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zero1 && zero2 && sign1 == sign2)
+ {
+ result = FPZero(sign1);
+ }
+ else
+ {
+ result = value1 + value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static int FPCompare(double value1, double value2, byte signalNaNs)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ int result;
+
+ if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
+ {
+ result = 0b0011;
+
+ if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs == 1)
+ {
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ }
+ else
+ {
+ if (value1 == value2)
+ {
+ result = 0b0110;
+ }
+ else if (value1 < value2)
+ {
+ result = 0b1000;
+ }
+ else
+ {
+ result = 0b0010;
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareEQ(double value1, double value2)
+ {
+ return FPCompareEQFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPCompareEQFpscrImpl(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ double result;
+
+ if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
+ {
+ result = ZerosOrOnes(false);
+
+ if (type1 == FPType.SNaN || type2 == FPType.SNaN)
+ {
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ }
+ else
+ {
+ result = ZerosOrOnes(value1 == value2);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareGE(double value1, double value2)
+ {
+ return FPCompareGEFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPCompareGEFpscrImpl(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ double result;
+
+ if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
+ {
+ result = ZerosOrOnes(false);
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else
+ {
+ result = ZerosOrOnes(value1 >= value2);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareGT(double value1, double value2)
+ {
+ return FPCompareGTFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPCompareGTFpscrImpl(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ double result;
+
+ if (type1 == FPType.SNaN || type1 == FPType.QNaN || type2 == FPType.SNaN || type2 == FPType.QNaN)
+ {
+ result = ZerosOrOnes(false);
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else
+ {
+ result = ZerosOrOnes(value1 > value2);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareLE(double value1, double value2)
+ {
+ return FPCompareGEFpscrImpl(value2, value1, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareLT(double value1, double value2)
+ {
+ return FPCompareGTFpscrImpl(value2, value1, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPDiv(double value1, double value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && inf2) || (zero1 && zero2))
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if (inf1 || zero2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+
+ if (!inf1)
+ {
+ SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
+ }
+ }
+ else if (zero1 || inf2)
+ {
+ result = FPZero(sign1 ^ sign2);
+ }
+ else
+ {
+ result = value1 / value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMax(double value1, double value2)
+ {
+ return FPMaxFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPMaxFpscrImpl(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ if (value1 > value2)
+ {
+ if (type1 == FPType.Infinity)
+ {
+ result = FPInfinity(sign1);
+ }
+ else if (type1 == FPType.Zero)
+ {
+ result = FPZero(sign1 && sign2);
+ }
+ else
+ {
+ result = value1;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+ else
+ {
+ if (type2 == FPType.Infinity)
+ {
+ result = FPInfinity(sign2);
+ }
+ else if (type2 == FPType.Zero)
+ {
+ result = FPZero(sign1 && sign2);
+ }
+ else
+ {
+ result = value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMaxNum(double value1, double value2)
+ {
+ return FPMaxNumFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPMaxNumFpscrImpl(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ if (type1 == FPType.QNaN && type2 != FPType.QNaN)
+ {
+ value1 = FPInfinity(true);
+ }
+ else if (type1 != FPType.QNaN && type2 == FPType.QNaN)
+ {
+ value2 = FPInfinity(true);
+ }
+
+ return FPMaxFpscrImpl(value1, value2, standardFpscr);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMin(double value1, double value2)
+ {
+ return FPMinFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPMinFpscrImpl(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ if (value1 < value2)
+ {
+ if (type1 == FPType.Infinity)
+ {
+ result = FPInfinity(sign1);
+ }
+ else if (type1 == FPType.Zero)
+ {
+ result = FPZero(sign1 || sign2);
+ }
+ else
+ {
+ result = value1;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+ else
+ {
+ if (type2 == FPType.Infinity)
+ {
+ result = FPInfinity(sign2);
+ }
+ else if (type2 == FPType.Zero)
+ {
+ result = FPZero(sign1 || sign2);
+ }
+ else
+ {
+ result = value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMinNum(double value1, double value2)
+ {
+ return FPMinNumFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPMinNumFpscrImpl(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1.FPUnpack(out FPType type1, out _, out _, context, fpcr);
+ value2.FPUnpack(out FPType type2, out _, out _, context, fpcr);
+
+ if (type1 == FPType.QNaN && type2 != FPType.QNaN)
+ {
+ value1 = FPInfinity(false);
+ }
+ else if (type1 != FPType.QNaN && type2 == FPType.QNaN)
+ {
+ value2 = FPInfinity(false);
+ }
+
+ return FPMinFpscrImpl(value1, value2, standardFpscr);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMul(double value1, double value2)
+ {
+ return FPMulFpscrImpl(value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
+ {
+ return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPMulFpscrImpl(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if (inf1 || inf2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+ }
+ else if (zero1 || zero2)
+ {
+ result = FPZero(sign1 ^ sign2);
+ }
+ else
+ {
+ result = value1 * value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMulAdd(double valueA, double value1, double value2)
+ {
+ return FPMulAddFpscrImpl(valueA, value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
+ {
+ return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
+ }
+
+ private static double FPMulAddFpscrImpl(double valueA, double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ valueA = valueA.FPUnpack(out FPType typeA, out bool signA, out ulong addend, context, fpcr);
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ double result = FPProcessNaNs3(typeA, type1, type2, addend, op1, op2, out bool done, context, fpcr);
+
+ if (typeA == FPType.QNaN && ((inf1 && zero2) || (zero1 && inf2)))
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+
+ if (!done)
+ {
+ bool infA = typeA == FPType.Infinity;
+ bool zeroA = typeA == FPType.Zero;
+
+ bool signP = sign1 ^ sign2;
+ bool infP = inf1 || inf2;
+ bool zeroP = zero1 || zero2;
+
+ if ((inf1 && zero2) || (zero1 && inf2) || (infA && infP && signA != signP))
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((infA && !signA) || (infP && !signP))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((infA && signA) || (infP && signP))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zeroA && zeroP && signA == signP)
+ {
+ result = FPZero(signA);
+ }
+ else
+ {
+ result = Math.FusedMultiplyAdd(value1, value2, valueA);
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMulSub(double valueA, double value1, double value2)
+ {
+ value1 = value1.FPNeg();
+
+ return FPMulAddFpscrImpl(valueA, value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
+ {
+ value1 = value1.FPNeg();
+
+ return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPMulX(double value1, double value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ result = FPTwo(sign1 ^ sign2);
+ }
+ else if (inf1 || inf2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+ }
+ else if (zero1 || zero2)
+ {
+ result = FPZero(sign1 ^ sign2);
+ }
+ else
+ {
+ result = value1 * value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPNegMulAdd(double valueA, double value1, double value2)
+ {
+ valueA = valueA.FPNeg();
+ value1 = value1.FPNeg();
+
+ return FPMulAddFpscrImpl(valueA, value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPNegMulSub(double valueA, double value1, double value2)
+ {
+ valueA = valueA.FPNeg();
+
+ return FPMulAddFpscrImpl(valueA, value1, value2, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPRecipEstimate(double value)
+ {
+ return FPRecipEstimateFpscrImpl(value, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
+ {
+ return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
+ }
+
+ private static double FPRecipEstimateFpscrImpl(double value, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
+
+ double result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ result = FPProcessNaN(type, op, context, fpcr);
+ }
+ else if (type == FPType.Infinity)
+ {
+ result = FPZero(sign);
+ }
+ else if (type == FPType.Zero)
+ {
+ result = FPInfinity(sign);
+
+ SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
+ }
+ else if (Math.Abs(value) < Math.Pow(2d, -1024))
+ {
+ bool overflowToInf = fpcr.RoundingMode switch
+ {
+ FPRoundingMode.ToNearest => true,
+ FPRoundingMode.TowardsPlusInfinity => !sign,
+ FPRoundingMode.TowardsMinusInfinity => sign,
+ FPRoundingMode.TowardsZero => false,
+ _ => throw new ArgumentException($"Invalid rounding mode \"{fpcr.RoundingMode}\"."),
+ };
+ result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
+
+ SoftFloat.FPProcessException(FPException.Overflow, context, fpcr);
+ SoftFloat.FPProcessException(FPException.Inexact, context, fpcr);
+ }
+ else if ((fpcr & FPCR.Fz) != 0 && (Math.Abs(value) >= Math.Pow(2d, 1022)))
+ {
+ result = FPZero(sign);
+
+ context.Fpsr |= FPSR.Ufc;
+ }
+ else
+ {
+ ulong fraction = op & 0x000FFFFFFFFFFFFFul;
+ uint exp = (uint)((op & 0x7FF0000000000000ul) >> 52);
+
+ if (exp == 0u)
+ {
+ if ((fraction & 0x0008000000000000ul) == 0ul)
+ {
+ fraction = (fraction & 0x0003FFFFFFFFFFFFul) << 2;
+ exp -= 1u;
+ }
+ else
+ {
+ fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
+ }
+ }
+
+ uint scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
+
+ uint resultExp = 2045u - exp;
+
+ uint estimate = (uint)SoftFloat.RecipEstimateTable[scaled - 256u] + 256u;
+
+ fraction = (ulong)(estimate & 0xFFu) << 44;
+
+ if (resultExp == 0u)
+ {
+ fraction = ((fraction & 0x000FFFFFFFFFFFFEul) | 0x0010000000000000ul) >> 1;
+ }
+ else if (resultExp + 1u == 0u)
+ {
+ fraction = ((fraction & 0x000FFFFFFFFFFFFCul) | 0x0010000000000000ul) >> 2;
+ resultExp = 0u;
+ }
+
+ result = BitConverter.Int64BitsToDouble(
+ (long)((sign ? 1ul : 0ul) << 63 | (resultExp & 0x7FFul) << 52 | (fraction & 0x000FFFFFFFFFFFFFul)));
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPRecipStep(double value1, double value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.StandardFpcrValue;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ double product;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ product = FPZero(false);
+ }
+ else
+ {
+ product = FPMulFpscrImpl(value1, value2, true);
+ }
+
+ result = FPSubFpscr(FPTwo(false), product, true);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPRecipStepFused(double value1, double value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPNeg();
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ result = FPTwo(false);
+ }
+ else if (inf1 || inf2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+ }
+ else
+ {
+ result = Math.FusedMultiplyAdd(value1, value2, 2d);
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPRecpX(double value)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
+
+ double result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ result = FPProcessNaN(type, op, context, fpcr);
+ }
+ else
+ {
+ ulong notExp = (~op >> 52) & 0x7FFul;
+ ulong maxExp = 0x7FEul;
+
+ result = BitConverter.Int64BitsToDouble(
+ (long)((sign ? 1ul : 0ul) << 63 | (notExp == 0x7FFul ? maxExp : notExp) << 52));
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPRSqrtEstimate(double value)
+ {
+ return FPRSqrtEstimateFpscrImpl(value, false);
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
+ {
+ return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
+ }
+
+ private static double FPRSqrtEstimateFpscrImpl(double value, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
+
+ double result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ result = FPProcessNaN(type, op, context, fpcr);
+ }
+ else if (type == FPType.Zero)
+ {
+ result = FPInfinity(sign);
+
+ SoftFloat.FPProcessException(FPException.DivideByZero, context, fpcr);
+ }
+ else if (sign)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if (type == FPType.Infinity)
+ {
+ result = FPZero(false);
+ }
+ else
+ {
+ ulong fraction = op & 0x000FFFFFFFFFFFFFul;
+ uint exp = (uint)((op & 0x7FF0000000000000ul) >> 52);
+
+ if (exp == 0u)
+ {
+ while ((fraction & 0x0008000000000000ul) == 0ul)
+ {
+ fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
+ exp -= 1u;
+ }
+
+ fraction = (fraction & 0x0007FFFFFFFFFFFFul) << 1;
+ }
+
+ uint scaled;
+
+ if ((exp & 1u) == 0u)
+ {
+ scaled = (uint)(((fraction & 0x000FF00000000000ul) | 0x0010000000000000ul) >> 44);
+ }
+ else
+ {
+ scaled = (uint)(((fraction & 0x000FE00000000000ul) | 0x0010000000000000ul) >> 45);
+ }
+
+ uint resultExp = (3068u - exp) >> 1;
+
+ uint estimate = (uint)SoftFloat.RecipSqrtEstimateTable[scaled - 128u] + 256u;
+
+ result = BitConverter.Int64BitsToDouble((long)((resultExp & 0x7FFul) << 52 | (estimate & 0xFFul) << 44));
+ }
+
+ return result;
+ }
+
+ public static double FPHalvedSub(double value1, double value2, ExecutionContext context, FPCR fpcr)
+ {
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if (inf1 && inf2 && sign1 == sign2)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((inf1 && !sign1) || (inf2 && sign2))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((inf1 && sign1) || (inf2 && !sign2))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zero1 && zero2 && sign1 == !sign2)
+ {
+ result = FPZero(sign1);
+ }
+ else
+ {
+ result = (value1 - value2) / 2.0;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPRSqrtStep(double value1, double value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.StandardFpcrValue;
+
+ value1 = value1.FPUnpack(out FPType type1, out _, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out _, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ double product;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ product = FPZero(false);
+ }
+ else
+ {
+ product = FPMulFpscrImpl(value1, value2, true);
+ }
+
+ result = FPHalvedSub(FPThree(false), product, context, fpcr);
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPRSqrtStepFused(double value1, double value2)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value1 = value1.FPNeg();
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if ((inf1 && zero2) || (zero1 && inf2))
+ {
+ result = FPOnePointFive(false);
+ }
+ else if (inf1 || inf2)
+ {
+ result = FPInfinity(sign1 ^ sign2);
+ }
+ else
+ {
+ result = Math.FusedMultiplyAdd(value1, value2, 3d) / 2d;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPSqrt(double value)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = context.Fpcr;
+
+ value = value.FPUnpack(out FPType type, out bool sign, out ulong op, context, fpcr);
+
+ double result;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ result = FPProcessNaN(type, op, context, fpcr);
+ }
+ else if (type == FPType.Zero)
+ {
+ result = FPZero(sign);
+ }
+ else if (type == FPType.Infinity && !sign)
+ {
+ result = FPInfinity(sign);
+ }
+ else if (sign)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else
+ {
+ result = Math.Sqrt(value);
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+
+ return result;
+ }
+
+ [UnmanagedCallersOnly]
+ public static double FPSub(double value1, double value2)
+ {
+ return FPSubFpscr(value1, value2, false);
+ }
+
+ public static double FPSubFpscr(double value1, double value2, bool standardFpscr)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+ FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
+
+ value1 = value1.FPUnpack(out FPType type1, out bool sign1, out ulong op1, context, fpcr);
+ value2 = value2.FPUnpack(out FPType type2, out bool sign2, out ulong op2, context, fpcr);
+
+ double result = FPProcessNaNs(type1, type2, op1, op2, out bool done, context, fpcr);
+
+ if (!done)
+ {
+ bool inf1 = type1 == FPType.Infinity;
+ bool zero1 = type1 == FPType.Zero;
+ bool inf2 = type2 == FPType.Infinity;
+ bool zero2 = type2 == FPType.Zero;
+
+ if (inf1 && inf2 && sign1 == sign2)
+ {
+ result = FPDefaultNaN();
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+ else if ((inf1 && !sign1) || (inf2 && sign2))
+ {
+ result = FPInfinity(false);
+ }
+ else if ((inf1 && sign1) || (inf2 && !sign2))
+ {
+ result = FPInfinity(true);
+ }
+ else if (zero1 && zero2 && sign1 == !sign2)
+ {
+ result = FPZero(sign1);
+ }
+ else
+ {
+ result = value1 - value2;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public static double FPDefaultNaN()
+ {
+ return BitConverter.Int64BitsToDouble(0x7ff8000000000000);
+ }
+
+ public static double FPInfinity(bool sign)
+ {
+ return sign ? double.NegativeInfinity : double.PositiveInfinity;
+ }
+
+ public static double FPZero(bool sign)
+ {
+ return sign ? -0d : +0d;
+ }
+
+ public static double FPMaxNormal(bool sign)
+ {
+ return sign ? double.MinValue : double.MaxValue;
+ }
+
+ private static double FPTwo(bool sign)
+ {
+ return sign ? -2d : +2d;
+ }
+
+ private static double FPThree(bool sign)
+ {
+ return sign ? -3d : +3d;
+ }
+
+ private static double FPOnePointFive(bool sign)
+ {
+ return sign ? -1.5d : +1.5d;
+ }
+
+ private static double FPNeg(this double value)
+ {
+ return -value;
+ }
+
+ private static double ZerosOrOnes(bool ones)
+ {
+ return BitConverter.Int64BitsToDouble(ones ? -1L : 0L);
+ }
+
+ private static double FPUnpack(
+ this double value,
+ out FPType type,
+ out bool sign,
+ out ulong valueBits,
+ ExecutionContext context,
+ FPCR fpcr)
+ {
+ valueBits = (ulong)BitConverter.DoubleToInt64Bits(value);
+
+ sign = (~valueBits & 0x8000000000000000ul) == 0ul;
+
+ if ((valueBits & 0x7FF0000000000000ul) == 0ul)
+ {
+ if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul || (fpcr & FPCR.Fz) != 0)
+ {
+ type = FPType.Zero;
+ value = FPZero(sign);
+
+ if ((valueBits & 0x000FFFFFFFFFFFFFul) != 0ul)
+ {
+ SoftFloat.FPProcessException(FPException.InputDenorm, context, fpcr);
+ }
+ }
+ else
+ {
+ type = FPType.Nonzero;
+ }
+ }
+ else if ((~valueBits & 0x7FF0000000000000ul) == 0ul)
+ {
+ if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul)
+ {
+ type = FPType.Infinity;
+ }
+ else
+ {
+ type = (~valueBits & 0x0008000000000000ul) == 0ul ? FPType.QNaN : FPType.SNaN;
+ value = FPZero(sign);
+ }
+ }
+ else
+ {
+ type = FPType.Nonzero;
+ }
+
+ return value;
+ }
+
+ private static double FPProcessNaNs(
+ FPType type1,
+ FPType type2,
+ ulong op1,
+ ulong op2,
+ out bool done,
+ ExecutionContext context,
+ FPCR fpcr)
+ {
+ done = true;
+
+ if (type1 == FPType.SNaN)
+ {
+ return FPProcessNaN(type1, op1, context, fpcr);
+ }
+ else if (type2 == FPType.SNaN)
+ {
+ return FPProcessNaN(type2, op2, context, fpcr);
+ }
+ else if (type1 == FPType.QNaN)
+ {
+ return FPProcessNaN(type1, op1, context, fpcr);
+ }
+ else if (type2 == FPType.QNaN)
+ {
+ return FPProcessNaN(type2, op2, context, fpcr);
+ }
+
+ done = false;
+
+ return FPZero(false);
+ }
+
+ private static double FPProcessNaNs3(
+ FPType type1,
+ FPType type2,
+ FPType type3,
+ ulong op1,
+ ulong op2,
+ ulong op3,
+ out bool done,
+ ExecutionContext context,
+ FPCR fpcr)
+ {
+ done = true;
+
+ if (type1 == FPType.SNaN)
+ {
+ return FPProcessNaN(type1, op1, context, fpcr);
+ }
+ else if (type2 == FPType.SNaN)
+ {
+ return FPProcessNaN(type2, op2, context, fpcr);
+ }
+ else if (type3 == FPType.SNaN)
+ {
+ return FPProcessNaN(type3, op3, context, fpcr);
+ }
+ else if (type1 == FPType.QNaN)
+ {
+ return FPProcessNaN(type1, op1, context, fpcr);
+ }
+ else if (type2 == FPType.QNaN)
+ {
+ return FPProcessNaN(type2, op2, context, fpcr);
+ }
+ else if (type3 == FPType.QNaN)
+ {
+ return FPProcessNaN(type3, op3, context, fpcr);
+ }
+
+ done = false;
+
+ return FPZero(false);
+ }
+
+ private static double FPProcessNaN(FPType type, ulong op, ExecutionContext context, FPCR fpcr)
+ {
+ if (type == FPType.SNaN)
+ {
+ op |= 1ul << 51;
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
+ }
+
+ if ((fpcr & FPCR.Dn) != 0)
+ {
+ return FPDefaultNaN();
+ }
+
+ return BitConverter.Int64BitsToDouble((long)op);
+ }
+ }
+}
diff --git a/src/ARMeilleure/Instructions/SoftFloat/SoftFloat64_16.cs b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat64_16.cs
new file mode 100644
index 000000000..71bc84da5
--- /dev/null
+++ b/src/ARMeilleure/Instructions/SoftFloat/SoftFloat64_16.cs
@@ -0,0 +1,127 @@
+using ARMeilleure.State;
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Instructions
+{
+ static class SoftFloat64_16
+ {
+ [UnmanagedCallersOnly]
+ public static ushort FPConvert(double value)
+ {
+ ExecutionContext context = NativeInterface.GetContext();
+
+ double real = value.FPUnpackCv(out FPType type, out bool sign, out ulong valueBits, context);
+
+ bool altHp = (context.Fpcr & FPCR.Ahp) != 0;
+
+ ushort resultBits;
+
+ if (type is FPType.SNaN or FPType.QNaN)
+ {
+ if (altHp)
+ {
+ resultBits = SoftFloat16.FPZero(sign);
+ }
+ else if ((context.Fpcr & FPCR.Dn) != 0)
+ {
+ resultBits = SoftFloat16.FPDefaultNaN();
+ }
+ else
+ {
+ resultBits = FPConvertNaN(valueBits);
+ }
+
+ if (type == FPType.SNaN || altHp)
+ {
+ SoftFloat.FPProcessException(FPException.InvalidOp, context);
+ }
+ }
+ else if (type == FPType.Infinity)
+ {
+ if (altHp)
+ {
+ resultBits = (ushort)((sign ? 1u : 0u) << 15 | 0x7FFFu);
+
+ SoftFloat.FPProcessException(FPException.InvalidOp, context);
+ }
+ else
+ {
+ resultBits = SoftFloat16.FPInfinity(sign);
+ }
+ }
+ else if (type == FPType.Zero)
+ {
+ resultBits = SoftFloat16.FPZero(sign);
+ }
+ else
+ {
+ resultBits = SoftFloat16.FPRoundCv(real, context);
+ }
+
+ return resultBits;
+ }
+
+ private static double FPUnpackCv(
+ this double value,
+ out FPType type,
+ out bool sign,
+ out ulong valueBits,
+ ExecutionContext context)
+ {
+ valueBits = (ulong)BitConverter.DoubleToInt64Bits(value);
+
+ sign = (~valueBits & 0x8000000000000000ul) == 0u;
+
+ ulong exp64 = (valueBits & 0x7FF0000000000000ul) >> 52;
+ ulong frac64 = valueBits & 0x000FFFFFFFFFFFFFul;
+
+ double real;
+
+ if (exp64 == 0u)
+ {
+ if (frac64 == 0u || (context.Fpcr & FPCR.Fz) != 0)
+ {
+ type = FPType.Zero;
+ real = 0d;
+
+ if (frac64 != 0u)
+ {
+ SoftFloat.FPProcessException(FPException.InputDenorm, context);
+ }
+ }
+ else
+ {
+ type = FPType.Nonzero; // Subnormal.
+ real = Math.Pow(2d, -1022) * ((double)frac64 * Math.Pow(2d, -52));
+ }
+ }
+ else if (exp64 == 0x7FFul)
+ {
+ if (frac64 == 0u)
+ {
+ type = FPType.Infinity;
+ real = Math.Pow(2d, 1000000);
+ }
+ else
+ {
+ type = (~frac64 & 0x0008000000000000ul) == 0u ? FPType.QNaN : FPType.SNaN;
+ real = 0d;
+ }
+ }
+ else
+ {
+ type = FPType.Nonzero; // Normal.
+ real = Math.Pow(2d, (int)exp64 - 1023) * (1d + (double)frac64 * Math.Pow(2d, -52));
+ }
+
+ return sign ? -real : real;
+ }
+
+ private static ushort FPConvertNaN(ulong valueBits)
+ {
+ return (ushort)((valueBits & 0x8000000000000000ul) >> 48 | 0x7E00u |
+ (valueBits & 0x0007FC0000000000ul) >> 42);
+ }
+ }
+}
diff --git a/src/ARMeilleure/IntermediateRepresentation/Comparison.cs b/src/ARMeilleure/IntermediateRepresentation/Comparison.cs
index 3d6a9d818..c9d3b5c76 100644
--- a/src/ARMeilleure/IntermediateRepresentation/Comparison.cs
+++ b/src/ARMeilleure/IntermediateRepresentation/Comparison.cs
@@ -16,9 +16,9 @@ namespace ARMeilleure.IntermediateRepresentation
static class ComparisonExtensions
{
- public static Comparison Invert(this Comparison comp)
+ extension(Comparison comparison)
{
- return (Comparison)((int)comp ^ 1);
+ public Comparison Inverse => (Comparison)((int)comparison ^ 1);
}
}
}
diff --git a/src/ARMeilleure/IntermediateRepresentation/OperandType.cs b/src/ARMeilleure/IntermediateRepresentation/OperandType.cs
index fec22eed6..027be8cac 100644
--- a/src/ARMeilleure/IntermediateRepresentation/OperandType.cs
+++ b/src/ARMeilleure/IntermediateRepresentation/OperandType.cs
@@ -14,48 +14,38 @@ namespace ARMeilleure.IntermediateRepresentation
static class OperandTypeExtensions
{
- public static bool IsInteger(this OperandType type)
+ extension(OperandType type)
{
- return type is OperandType.I32 or
- OperandType.I64;
- }
-
- public static RegisterType ToRegisterType(this OperandType type)
- {
- return type switch
+ public bool IsInteger => type is OperandType.I32 or OperandType.I64;
+
+ public RegisterType Register => type switch
{
OperandType.FP32 => RegisterType.Vector,
OperandType.FP64 => RegisterType.Vector,
OperandType.I32 => RegisterType.Integer,
OperandType.I64 => RegisterType.Integer,
OperandType.V128 => RegisterType.Vector,
- _ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
+ _ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
- }
-
- public static int GetSizeInBytes(this OperandType type)
- {
- return type switch
+
+ public int ByteSize => type switch
{
OperandType.FP32 => 4,
OperandType.FP64 => 8,
OperandType.I32 => 4,
OperandType.I64 => 8,
OperandType.V128 => 16,
- _ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
+ _ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
- }
-
- public static int GetSizeInBytesLog2(this OperandType type)
- {
- return type switch
+
+ public int ByteSizeLog2 => type switch
{
OperandType.FP32 => 2,
OperandType.FP64 => 3,
OperandType.I32 => 2,
OperandType.I64 => 3,
OperandType.V128 => 4,
- _ => throw new InvalidOperationException($"Invalid operand type \"{type}\"."),
+ _ => throw new InvalidOperationException($"Invalid operand type \"{type}\".")
};
}
}
diff --git a/src/ARMeilleure/Memory/MemoryManagerType.cs b/src/ARMeilleure/Memory/MemoryManagerType.cs
index cad7c3558..ce417ee7e 100644
--- a/src/ARMeilleure/Memory/MemoryManagerType.cs
+++ b/src/ARMeilleure/Memory/MemoryManagerType.cs
@@ -45,19 +45,12 @@ namespace ARMeilleure.Memory
public static class MemoryManagerTypeExtensions
{
- public static bool IsHostMapped(this MemoryManagerType type)
+ extension(MemoryManagerType type)
{
- return type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
- }
-
- public static bool IsHostTracked(this MemoryManagerType type)
- {
- return type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
- }
-
- public static bool IsHostMappedOrTracked(this MemoryManagerType type)
- {
- return type.IsHostMapped() || type.IsHostTracked();
+ public bool IsHostMapped => type is MemoryManagerType.HostMapped or MemoryManagerType.HostMappedUnsafe;
+ public bool IsHostTracked => type is MemoryManagerType.HostTracked or MemoryManagerType.HostTrackedUnsafe;
+
+ public bool IsHostMappedOrTracked => type.IsHostMapped || type.IsHostTracked;
}
}
}
diff --git a/src/ARMeilleure/Translation/Translator.cs b/src/ARMeilleure/Translation/Translator.cs
index 073b7ffe2..0ebb705a4 100644
--- a/src/ARMeilleure/Translation/Translator.cs
+++ b/src/ARMeilleure/Translation/Translator.cs
@@ -412,7 +412,7 @@ namespace ARMeilleure.Translation
{
context.SyncQcFlag();
- if (block.Branch != null && !block.Branch.Exit && block.Branch.Address <= block.Address)
+ if (block.Branch is { Exit: false } && block.Branch.Address <= block.Address)
{
EmitSynchronization(context);
}
@@ -429,14 +429,14 @@ namespace ARMeilleure.Translation
{
lblPredicateSkip = Label();
- InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Invert());
+ InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Inverse);
}
- if (opCode is OpCode32 op && op.Cond < Condition.Al)
+ if (opCode is OpCode32 { Cond: < Condition.Al } op)
{
lblPredicateSkip = Label();
- InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert());
+ InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Inverse);
}
if (opCode.Instruction.Emitter != null)
diff --git a/src/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs b/src/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs
index a9acabec9..0410314c4 100644
--- a/src/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs
+++ b/src/Ryujinx.Audio/Backends/CompatLayer/CompatLayerHardwareDeviceSession.cs
@@ -58,16 +58,16 @@ namespace Ryujinx.Audio.Backends.CompatLayer
switch (realSampleFormat)
{
case SampleFormat.PcmInt8:
- PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast(convertedSamples), samples);
+ PcmHelper.ConvertSampleToPcm8(MemoryMarshal.Cast(new Span(convertedSamples)), samples);
break;
case SampleFormat.PcmInt24:
PcmHelper.ConvertSampleToPcm24(convertedSamples, samples);
break;
case SampleFormat.PcmInt32:
- PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast(convertedSamples), samples);
+ PcmHelper.ConvertSampleToPcm32(MemoryMarshal.Cast(new Span(convertedSamples)), samples);
break;
case SampleFormat.PcmFloat:
- PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast(convertedSamples), samples);
+ PcmHelper.ConvertSampleToPcmFloat(MemoryMarshal.Cast(new Span(convertedSamples)), samples);
break;
default:
throw new NotImplementedException($"Sample format conversion from {_userSampleFormat} to {realSampleFormat} not implemented.");
diff --git a/src/Ryujinx.Audio/Integration/HardwareDeviceImpl.cs b/src/Ryujinx.Audio/Integration/HardwareDeviceImpl.cs
index 1369f953a..32457d09a 100644
--- a/src/Ryujinx.Audio/Integration/HardwareDeviceImpl.cs
+++ b/src/Ryujinx.Audio/Integration/HardwareDeviceImpl.cs
@@ -27,7 +27,7 @@ namespace Ryujinx.Audio.Integration
public void AppendBuffer(ReadOnlySpan data, uint channelCount)
{
- data.CopyTo(MemoryMarshal.Cast(_buffer));
+ data.CopyTo(MemoryMarshal.Cast(new Span(_buffer)));
_session.QueueBuffer(new AudioBuffer
{
diff --git a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
index a29def8e8..9b2bf7015 100644
--- a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
+++ b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
@@ -17,7 +17,7 @@ namespace Ryujinx.Cpu.Jit
_functionTable = AddressTable.CreateForArm(for64Bit, memory.Type);
_translator = new Translator(new JitMemoryAllocator(forJit: true), memory, _functionTable);
- if (memory.Type.IsHostMappedOrTracked())
+ if (memory.Type.IsHostMappedOrTracked)
{
NativeSignalHandler.InitializeSignalHandler();
}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/ScopedRegister.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/ScopedRegister.cs
index 18b1416ea..e4ebf1309 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm32/ScopedRegister.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/ScopedRegister.cs
@@ -26,7 +26,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32
return;
}
- if (_operand.Type.IsInteger())
+ if (_operand.Type.IsInteger)
{
_registerAllocator.FreeTempGprRegister(_operand.AsInt32());
}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs
index 643d1e20d..ff11cbd41 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs
@@ -381,7 +381,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
if (currentCond != ArmCondition.Al)
{
instructionPointer = context.CodeWriter.InstructionPointer;
- context.Arm64Assembler.B(currentCond.Invert(), 0);
+ context.Arm64Assembler.B(currentCond.Inverse, 0);
}
}
}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs
index 8190bd7ea..943bc6897 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs
@@ -104,7 +104,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
if (invert)
{
- conditions[i++] = ((ArmCondition)firstCond).Invert();
+ conditions[i++] = ((ArmCondition)firstCond).Inverse;
}
else
{
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs
index d8caee6e7..761335c47 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs
@@ -1129,7 +1129,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
// We don't need to mask the address for the safe mode, since it is already naturally limited to 32-bit
// and can never reach out of the guest address space.
- if (mmType.IsHostTracked())
+ if (mmType.IsHostTracked)
{
int tempRegister = regAlloc.AllocateTempGprRegister();
@@ -1141,7 +1141,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
regAlloc.FreeTempGprRegister(tempRegister);
}
- else if (mmType.IsHostMapped())
+ else if (mmType.IsHostMapped)
{
asm.Add(destination64, basePointer, guestAddress);
}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs
index 405126357..43ad1b3b6 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs
@@ -132,7 +132,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
InstName lastInstructionName = Instructions[^1].Name;
- return lastInstructionName.IsCall() || lastInstructionName.IsException();
+ return lastInstructionName.IsCall || lastInstructionName.IsException;
}
}
}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs
index af3b872a5..8a937134f 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs
@@ -1042,126 +1042,39 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
static class InstNameExtensions
{
- public static bool IsCall(this InstName name)
+ extension(InstName name)
{
- return name is InstName.Bl or InstName.Blr;
- }
+ public bool IsCall => name is InstName.Bl or InstName.Blr;
- public static bool IsControlFlowOrException(this InstName name)
- {
- switch (name)
+ public bool IsControlFlowOrException => name is
+ InstName.BUncond or InstName.BCond or InstName.Bl or InstName.Blr or InstName.Br or InstName.Brk
+ or InstName.Cbnz or InstName.Cbz or InstName.Ret or InstName.Tbnz or InstName.Tbz or InstName.Svc
+ or InstName.UdfPermUndef;
+
+ public bool IsException => name is InstName.Brk or InstName.Svc or InstName.UdfPermUndef;
+
+ public bool IsSystem => name switch
{
- case InstName.BUncond:
- case InstName.BCond:
- case InstName.Bl:
- case InstName.Blr:
- case InstName.Br:
- case InstName.Brk:
- case InstName.Cbnz:
- case InstName.Cbz:
- case InstName.Ret:
- case InstName.Tbnz:
- case InstName.Tbz:
- case InstName.Svc:
- case InstName.UdfPermUndef:
- return true;
- }
+ InstName.Mrs or InstName.MsrImm or InstName.MsrReg => true,
+ _ => name.IsException
+ };
- return false;
- }
+ public bool IsSystemOrCall => name.IsCall || name is
+ InstName.Svc or InstName.Mrs or InstName.MsrImm or InstName.MsrReg
+ or InstName.Sysl;
- public static bool IsException(this InstName name)
- {
- switch (name)
- {
- case InstName.Brk:
- case InstName.Svc:
- case InstName.UdfPermUndef:
- return true;
- }
+ public bool IsPrivileged => name is
+ InstName.Dcps1 or InstName.Dcps2 or InstName.Dcps3 or InstName.Drps or InstName.Eret or InstName.Ereta
+ or InstName.Hvc or InstName.MsrImm or InstName.Smc;
- return false;
- }
+ public bool IsPartialRegisterUpdateMemory => name is
+ InstName.Ld1AdvsimdSnglAsNoPostIndex or InstName.Ld1AdvsimdSnglAsPostIndex
+ or InstName.Ld2AdvsimdSnglAsNoPostIndex or InstName.Ld2AdvsimdSnglAsPostIndex
+ or InstName.Ld3AdvsimdSnglAsNoPostIndex or InstName.Ld3AdvsimdSnglAsPostIndex
+ or InstName.Ld4AdvsimdSnglAsNoPostIndex or InstName.Ld4AdvsimdSnglAsPostIndex;
- public static bool IsSystem(this InstName name)
- {
- switch (name)
- {
- case InstName.Mrs:
- case InstName.MsrImm:
- case InstName.MsrReg:
- return true;
- }
-
- return name.IsException();
- }
-
- public static bool IsSystemOrCall(this InstName name)
- {
- switch (name)
- {
- case InstName.Bl:
- case InstName.Blr:
- case InstName.Svc:
- case InstName.Mrs:
- case InstName.MsrImm:
- case InstName.MsrReg:
- case InstName.Sysl:
- return true;
- }
-
- return false;
- }
-
- public static bool IsPrivileged(this InstName name)
- {
- switch (name)
- {
- case InstName.Dcps1:
- case InstName.Dcps2:
- case InstName.Dcps3:
- case InstName.Drps:
- case InstName.Eret:
- case InstName.Ereta:
- case InstName.Hvc:
- case InstName.MsrImm:
- case InstName.Smc:
- return true;
- }
-
- return false;
- }
-
- public static bool IsPartialRegisterUpdateMemory(this InstName name)
- {
- switch (name)
- {
- case InstName.Ld1AdvsimdSnglAsNoPostIndex:
- case InstName.Ld1AdvsimdSnglAsPostIndex:
- case InstName.Ld2AdvsimdSnglAsNoPostIndex:
- case InstName.Ld2AdvsimdSnglAsPostIndex:
- case InstName.Ld3AdvsimdSnglAsNoPostIndex:
- case InstName.Ld3AdvsimdSnglAsPostIndex:
- case InstName.Ld4AdvsimdSnglAsNoPostIndex:
- case InstName.Ld4AdvsimdSnglAsPostIndex:
- return true;
- }
-
- return false;
- }
-
- public static bool IsPrefetchMemory(this InstName name)
- {
- switch (name)
- {
- case InstName.PrfmImm:
- case InstName.PrfmLit:
- case InstName.PrfmReg:
- case InstName.Prfum:
- return true;
- }
-
- return false;
+ public bool IsPrefetchMemory => name is
+ InstName.PrfmImm or InstName.PrfmLit or InstName.PrfmReg or InstName.Prfum;
}
}
}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs
index 1c6eab0de..425575df6 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs
@@ -150,7 +150,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
public static int CalculateMaxTemps(MemoryManagerType mmType)
{
- return mmType.IsHostMapped() ? 1 : 2;
+ return mmType.IsHostMapped ? 1 : 2;
}
public static int CalculateMaxTempsInclFixed(MemoryManagerType mmType)
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs
index 191e03e7b..c0ee93518 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs
@@ -247,7 +247,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
}
}
- if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory())
+ if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory)
{
if (flags.HasFlag(InstFlags.Rt))
{
@@ -281,7 +281,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64
gprMask |= MaskFromIndex(ExtractRd(flags, encoding));
}
- if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory())
+ if (!flags.HasFlag(InstFlags.ReadRt) || name.IsPartialRegisterUpdateMemory)
{
if (flags.HasFlag(InstFlags.Rt))
{
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs
index e45d74f9b..ac389f4ce 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs
@@ -364,7 +364,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
{
InstEmitMemory.RewriteSysInstruction(memoryManager.AddressSpaceBits, memoryManager.Type, writer, regAlloc, encoding);
}
- else if (instInfo.Name.IsSystem())
+ else if (instInfo.Name.IsSystem)
{
bool needsContextStoreLoad = InstEmitSystem.NeedsContextStoreLoad(instInfo.Name);
@@ -405,7 +405,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
lastInstructionEncoding = RegisterUtils.RemapRegisters(regAlloc, lastInstructionFlags, lastInstructionEncoding);
- if (lastInstructionName.IsCall())
+ if (lastInstructionName.IsCall)
{
context.StoreToContextBeforeCall(blockIndex, pc + 4UL);
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs
index ad221c7aa..931c7381e 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs
@@ -257,7 +257,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
(name, flags, AddressForm addressForm) = InstTable.GetInstNameAndFlags(encoding, cpuPreset.Version, cpuPreset.Features);
- if (name.IsPrivileged() || (name == InstName.Sys && IsPrivilegedSys(encoding)))
+ if (name.IsPrivileged || (name == InstName.Sys && IsPrivilegedSys(encoding)))
{
name = InstName.UdfPermUndef;
flags = InstFlags.None;
@@ -267,7 +267,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
(uint instGprReadMask, uint instFpSimdReadMask) = RegisterUtils.PopulateReadMasks(name, flags, encoding);
(uint instGprWriteMask, uint instFpSimdWriteMask) = RegisterUtils.PopulateWriteMasks(name, flags, encoding);
- if (name.IsCall())
+ if (name.IsCall)
{
instGprWriteMask |= 1u << RegisterUtils.LrIndex;
}
@@ -310,12 +310,12 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
fpSimdUseMask |= instFpSimdReadMask | instFpSimdWriteMask;
pStateUseMask |= instPStateReadMask | instPStateWriteMask;
- if (name.IsSystemOrCall() && !hasHostCall)
+ if (name.IsSystemOrCall && !hasHostCall)
{
- hasHostCall = name.IsCall() || InstEmitSystem.NeedsCall(encoding);
+ hasHostCall = name.IsCall || InstEmitSystem.NeedsCall(encoding);
}
- isControlFlow = name.IsControlFlowOrException();
+ isControlFlow = name.IsControlFlowOrException;
RegisterUse registerUse = new(
instGprReadMask,
@@ -339,7 +339,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
useMask = new(gprUseMask, fpSimdUseMask, pStateUseMask);
- return new(startAddress, address, insts, !isTruncated && !name.IsException(), isTruncated, isLoopEnd);
+ return new(startAddress, address, insts, !isTruncated && !name.IsException, isTruncated, isLoopEnd);
}
private static bool IsPrivilegedSys(uint encoding)
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs
index 790a7de95..e9d6c5c86 100644
--- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs
@@ -55,7 +55,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
ulong pc,
uint encoding)
{
- if (name.IsPrefetchMemory() && mmType == MemoryManagerType.HostTrackedUnsafe)
+ if (name.IsPrefetchMemory && mmType == MemoryManagerType.HostTrackedUnsafe)
{
// Prefetch to invalid addresses do not cause faults, so for memory manager
// types where we need to access the page table before doing the prefetch,
@@ -544,7 +544,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
{
Operand basePointer = new(regAlloc.FixedPageTableRegister, RegisterType.Integer, OperandType.I64);
- if (mmType.IsHostTracked())
+ if (mmType.IsHostTracked)
{
int tempRegister = regAlloc.AllocateTempGprRegister();
@@ -562,7 +562,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
regAlloc.FreeTempGprRegister(tempRegister);
}
- else if (mmType.IsHostMapped())
+ else if (mmType.IsHostMapped)
{
if (mmType == MemoryManagerType.HostMapped)
{
diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmCondition.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmCondition.cs
index caa2e593b..9293b497a 100644
--- a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmCondition.cs
+++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmCondition.cs
@@ -22,9 +22,9 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
static class ArmConditionExtensions
{
- public static ArmCondition Invert(this ArmCondition condition)
+ extension(ArmCondition condition)
{
- return (ArmCondition)((int)condition ^ 1);
+ public ArmCondition Inverse => (ArmCondition)((int)condition ^ 1);
}
}
}
diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/Assembler.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/Assembler.cs
index 3eeda20bf..f6eb226ec 100644
--- a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/Assembler.cs
+++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/Assembler.cs
@@ -673,7 +673,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
public readonly void Mov(Operand rd, Operand rn)
{
- Debug.Assert(rd.Type.IsInteger());
+ Debug.Assert(rd.Type.IsInteger);
Orr(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type), rn);
}
@@ -4544,7 +4544,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
uint instruction;
int scale;
- if (type.IsInteger())
+ if (type.IsInteger)
{
instruction = intInst;
@@ -4580,7 +4580,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
{
uint instruction;
- if (type.IsInteger())
+ if (type.IsInteger)
{
instruction = intInst;
@@ -4610,7 +4610,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
{
uint instruction;
- if (type.IsInteger())
+ if (type.IsInteger)
{
instruction = intInst;
diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/RegisterSaveRestore.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/RegisterSaveRestore.cs
index b4b8bb524..527448e1c 100644
--- a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/RegisterSaveRestore.cs
+++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/RegisterSaveRestore.cs
@@ -34,7 +34,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
int gprCalleeSavedRegsCount = BitOperations.PopCount(_gprMask);
int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(_fpSimdMask);
- return (_hasCall ? 16 : 0) + Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes());
+ return (_hasCall ? 16 : 0) + Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize);
}
public void WritePrologue(ref Assembler asm)
@@ -46,7 +46,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(fpSimdMask);
int reservedStackSize = Align16(_reservedStackSize);
- int calleeSaveRegionSize = Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes()) + reservedStackSize;
+ int calleeSaveRegionSize = Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize) + reservedStackSize;
int offset = 0;
WritePrologueCalleeSavesPreIndexed(ref asm, ref gprMask, ref offset, calleeSaveRegionSize, OperandType.I64);
@@ -103,7 +103,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
asm.StrRiUn(Register(reg, type), Register(Assembler.SpRegister), 0);
}
- offset += type.GetSizeInBytes();
+ offset += type.ByteSize;
}
while (mask != 0)
@@ -130,7 +130,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
asm.StpRiUn(Register(reg, type), Register(reg2, type), Register(Assembler.SpRegister), 0);
}
- offset += type.GetSizeInBytes() * 2;
+ offset += type.ByteSize * 2;
}
}
@@ -144,7 +144,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
bool misalignedVector = _fpSimdType == OperandType.V128 && (gprCalleeSavedRegsCount & 1) != 0;
- int offset = gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes();
+ int offset = gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.ByteSize;
if (misalignedVector)
{
@@ -197,7 +197,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
mask &= ~(1u << reg2);
- offset -= type.GetSizeInBytes() * 2;
+ offset -= type.ByteSize * 2;
if (offset != 0)
{
@@ -215,7 +215,7 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
}
else
{
- offset -= type.GetSizeInBytes();
+ offset -= type.ByteSize;
if (offset != 0)
{
diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandType.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandType.cs
index cd36c6781..ddb33167e 100644
--- a/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandType.cs
+++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandType.cs
@@ -14,14 +14,11 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen
static class OperandTypeExtensions
{
- public static bool IsInteger(this OperandType type)
+ extension(OperandType type)
{
- return type is OperandType.I32 or OperandType.I64;
- }
+ public bool IsInteger => type is OperandType.I32 or OperandType.I64;
- public static int GetSizeInBytes(this OperandType type)
- {
- return type switch
+ public int ByteSize => type switch
{
OperandType.FP32 => 4,
OperandType.FP64 => 8,
diff --git a/src/Ryujinx.Cpu/LightningJit/Translator.cs b/src/Ryujinx.Cpu/LightningJit/Translator.cs
index f3ae0a9c5..1ee6993d2 100644
--- a/src/Ryujinx.Cpu/LightningJit/Translator.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Translator.cs
@@ -48,7 +48,7 @@ namespace Ryujinx.Cpu.LightningJit
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
- if (memory.Type.IsHostMappedOrTracked())
+ if (memory.Type.IsHostMappedOrTracked)
{
NativeSignalHandler.InitializeSignalHandler();
}
diff --git a/src/Ryujinx.Graphics.GAL/BlendFactor.cs b/src/Ryujinx.Graphics.GAL/BlendFactor.cs
index 1dba229d6..99f946c3c 100644
--- a/src/Ryujinx.Graphics.GAL/BlendFactor.cs
+++ b/src/Ryujinx.Graphics.GAL/BlendFactor.cs
@@ -41,22 +41,12 @@ namespace Ryujinx.Graphics.GAL
public static class BlendFactorExtensions
{
- public static bool IsDualSource(this BlendFactor factor)
+ extension(BlendFactor factor)
{
- switch (factor)
- {
- case BlendFactor.Src1Color:
- case BlendFactor.Src1ColorGl:
- case BlendFactor.Src1Alpha:
- case BlendFactor.Src1AlphaGl:
- case BlendFactor.OneMinusSrc1Color:
- case BlendFactor.OneMinusSrc1ColorGl:
- case BlendFactor.OneMinusSrc1Alpha:
- case BlendFactor.OneMinusSrc1AlphaGl:
- return true;
- default:
- return false;
- }
+ public bool IsDualSource => factor is
+ BlendFactor.Src1Color or BlendFactor.Src1ColorGl or BlendFactor.Src1Alpha or BlendFactor.Src1AlphaGl
+ or BlendFactor.OneMinusSrc1Color or BlendFactor.OneMinusSrc1ColorGl or BlendFactor.OneMinusSrc1Alpha
+ or BlendFactor.OneMinusSrc1AlphaGl;
}
}
}
diff --git a/src/Ryujinx.Graphics.GAL/BufferHandle.cs b/src/Ryujinx.Graphics.GAL/BufferHandle.cs
index 7994e4eea..b8550a848 100644
--- a/src/Ryujinx.Graphics.GAL/BufferHandle.cs
+++ b/src/Ryujinx.Graphics.GAL/BufferHandle.cs
@@ -1,3 +1,4 @@
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.GAL
@@ -10,5 +11,7 @@ namespace Ryujinx.Graphics.GAL
public static BufferHandle Null => new(0);
private BufferHandle(ulong value) => _value = value;
+
+ public static implicit operator int(BufferHandle handle) => (int)Unsafe.As(ref handle);
}
}
diff --git a/src/Ryujinx.Graphics.GAL/Format.cs b/src/Ryujinx.Graphics.GAL/Format.cs
index 25446f978..277276fe3 100644
--- a/src/Ryujinx.Graphics.GAL/Format.cs
+++ b/src/Ryujinx.Graphics.GAL/Format.cs
@@ -159,589 +159,191 @@ namespace Ryujinx.Graphics.GAL
///
public const int MaxBufferFormatScalarSize = 4;
- ///
- /// Gets the byte size for a single component of this format, or its packed size.
- ///
- /// Texture format
- /// Byte size for a single component, or packed size
- public static int GetScalarSize(this Format format)
+ extension(Format fmt)
{
- switch (format)
+ ///
+ /// Gets the byte size for a single component of this format, or its packed size.
+ ///
+ public int ScalarSize => fmt switch
{
- case Format.R8Unorm:
- case Format.R8Snorm:
- case Format.R8Uint:
- case Format.R8Sint:
- case Format.R8G8Unorm:
- case Format.R8G8Snorm:
- case Format.R8G8Uint:
- case Format.R8G8Sint:
- case Format.R8G8B8Unorm:
- case Format.R8G8B8Snorm:
- case Format.R8G8B8Uint:
- case Format.R8G8B8Sint:
- case Format.R8G8B8A8Unorm:
- case Format.R8G8B8A8Snorm:
- case Format.R8G8B8A8Uint:
- case Format.R8G8B8A8Sint:
- case Format.R8G8B8A8Srgb:
- case Format.R4G4Unorm:
- case Format.R8Uscaled:
- case Format.R8Sscaled:
- case Format.R8G8Uscaled:
- case Format.R8G8Sscaled:
- case Format.R8G8B8Uscaled:
- case Format.R8G8B8Sscaled:
- case Format.R8G8B8A8Uscaled:
- case Format.R8G8B8A8Sscaled:
- case Format.B8G8R8A8Unorm:
- case Format.B8G8R8A8Srgb:
- return 1;
+ Format.R8Unorm or Format.R8Snorm or Format.R8Uint or Format.R8Sint or Format.R8G8Unorm
+ or Format.R8G8Snorm or Format.R8G8Uint or Format.R8G8Sint or Format.R8G8B8Unorm
+ or Format.R8G8B8Snorm or Format.R8G8B8Uint or Format.R8G8B8Sint or Format.R8G8B8A8Unorm
+ or Format.R8G8B8A8Snorm or Format.R8G8B8A8Uint or Format.R8G8B8A8Sint or Format.R8G8B8A8Srgb
+ or Format.R4G4Unorm or Format.R8Uscaled or Format.R8Sscaled or Format.R8G8Uscaled
+ or Format.R8G8Sscaled or Format.R8G8B8Uscaled or Format.R8G8B8Sscaled or Format.R8G8B8A8Uscaled
+ or Format.R8G8B8A8Sscaled or Format.B8G8R8A8Unorm or Format.B8G8R8A8Srgb => 1,
+ Format.R16Float or Format.R16Unorm or Format.R16Snorm or Format.R16Uint or Format.R16Sint
+ or Format.R16G16Float or Format.R16G16Unorm or Format.R16G16Snorm or Format.R16G16Uint
+ or Format.R16G16Sint or Format.R16G16B16Float or Format.R16G16B16Unorm or Format.R16G16B16Snorm
+ or Format.R16G16B16Uint or Format.R16G16B16Sint or Format.R16G16B16A16Float
+ or Format.R16G16B16A16Unorm or Format.R16G16B16A16Snorm or Format.R16G16B16A16Uint
+ or Format.R16G16B16A16Sint or Format.R4G4B4A4Unorm or Format.R5G5B5X1Unorm or Format.R5G5B5A1Unorm
+ or Format.R5G6B5Unorm or Format.R16Uscaled or Format.R16Sscaled or Format.R16G16Uscaled
+ or Format.R16G16Sscaled or Format.R16G16B16Uscaled or Format.R16G16B16Sscaled
+ or Format.R16G16B16A16Uscaled or Format.R16G16B16A16Sscaled or Format.B5G6R5Unorm
+ or Format.B5G5R5A1Unorm or Format.A1B5G5R5Unorm => 2,
+ Format.R32Float or Format.R32Uint or Format.R32Sint or Format.R32G32Float or Format.R32G32Uint
+ or Format.R32G32Sint or Format.R32G32B32Float or Format.R32G32B32Uint or Format.R32G32B32Sint
+ or Format.R32G32B32A32Float or Format.R32G32B32A32Uint or Format.R32G32B32A32Sint
+ or Format.R10G10B10A2Unorm or Format.R10G10B10A2Uint or Format.R11G11B10Float
+ or Format.R9G9B9E5Float or Format.R32Uscaled or Format.R32Sscaled or Format.R32G32Uscaled
+ or Format.R32G32Sscaled or Format.R32G32B32Uscaled or Format.R32G32B32Sscaled
+ or Format.R32G32B32A32Uscaled or Format.R32G32B32A32Sscaled or Format.R10G10B10A2Snorm
+ or Format.R10G10B10A2Sint or Format.R10G10B10A2Uscaled or Format.R10G10B10A2Sscaled
+ or Format.B10G10R10A2Unorm => 4,
+ Format.S8Uint => 1,
+ Format.D16Unorm => 2,
+ Format.S8UintD24Unorm or Format.X8UintD24Unorm or Format.D32Float or Format.D24UnormS8Uint => 4,
+ Format.D32FloatS8Uint => 8,
+ Format.Bc1RgbaUnorm or Format.Bc1RgbaSrgb => 8,
+ Format.Bc2Unorm or Format.Bc3Unorm or Format.Bc2Srgb or Format.Bc3Srgb or Format.Bc4Unorm
+ or Format.Bc4Snorm or Format.Bc5Unorm or Format.Bc5Snorm or Format.Bc7Unorm or Format.Bc7Srgb
+ or Format.Bc6HSfloat or Format.Bc6HUfloat => 16,
+ Format.Etc2RgbUnorm or Format.Etc2RgbPtaUnorm or Format.Etc2RgbSrgb or Format.Etc2RgbPtaSrgb => 8,
+ Format.Etc2RgbaUnorm or Format.Etc2RgbaSrgb => 16,
+ Format.Astc4x4Unorm or Format.Astc5x4Unorm or Format.Astc5x5Unorm or Format.Astc6x5Unorm
+ or Format.Astc6x6Unorm or Format.Astc8x5Unorm or Format.Astc8x6Unorm or Format.Astc8x8Unorm
+ or Format.Astc10x5Unorm or Format.Astc10x6Unorm or Format.Astc10x8Unorm or Format.Astc10x10Unorm
+ or Format.Astc12x10Unorm or Format.Astc12x12Unorm or Format.Astc4x4Srgb or Format.Astc5x4Srgb
+ or Format.Astc5x5Srgb or Format.Astc6x5Srgb or Format.Astc6x6Srgb or Format.Astc8x5Srgb
+ or Format.Astc8x6Srgb or Format.Astc8x8Srgb or Format.Astc10x5Srgb or Format.Astc10x6Srgb
+ or Format.Astc10x8Srgb or Format.Astc10x10Srgb or Format.Astc12x10Srgb
+ or Format.Astc12x12Srgb => 16,
+ _ => 1
+ };
- case Format.R16Float:
- case Format.R16Unorm:
- case Format.R16Snorm:
- case Format.R16Uint:
- case Format.R16Sint:
- case Format.R16G16Float:
- case Format.R16G16Unorm:
- case Format.R16G16Snorm:
- case Format.R16G16Uint:
- case Format.R16G16Sint:
- case Format.R16G16B16Float:
- case Format.R16G16B16Unorm:
- case Format.R16G16B16Snorm:
- case Format.R16G16B16Uint:
- case Format.R16G16B16Sint:
- case Format.R16G16B16A16Float:
- case Format.R16G16B16A16Unorm:
- case Format.R16G16B16A16Snorm:
- case Format.R16G16B16A16Uint:
- case Format.R16G16B16A16Sint:
- case Format.R4G4B4A4Unorm:
- case Format.R5G5B5X1Unorm:
- case Format.R5G5B5A1Unorm:
- case Format.R5G6B5Unorm:
- case Format.R16Uscaled:
- case Format.R16Sscaled:
- case Format.R16G16Uscaled:
- case Format.R16G16Sscaled:
- case Format.R16G16B16Uscaled:
- case Format.R16G16B16Sscaled:
- case Format.R16G16B16A16Uscaled:
- case Format.R16G16B16A16Sscaled:
- case Format.B5G6R5Unorm:
- case Format.B5G5R5A1Unorm:
- case Format.A1B5G5R5Unorm:
- return 2;
+ ///
+ /// Checks if the texture format is a depth or depth-stencil format.
+ ///
+ public bool HasDepth => fmt is
+ Format.D16Unorm or Format.D24UnormS8Uint or Format.S8UintD24Unorm or Format.X8UintD24Unorm
+ or Format.D32Float or Format.D32FloatS8Uint;
- case Format.R32Float:
- case Format.R32Uint:
- case Format.R32Sint:
- case Format.R32G32Float:
- case Format.R32G32Uint:
- case Format.R32G32Sint:
- case Format.R32G32B32Float:
- case Format.R32G32B32Uint:
- case Format.R32G32B32Sint:
- case Format.R32G32B32A32Float:
- case Format.R32G32B32A32Uint:
- case Format.R32G32B32A32Sint:
- case Format.R10G10B10A2Unorm:
- case Format.R10G10B10A2Uint:
- case Format.R11G11B10Float:
- case Format.R9G9B9E5Float:
- case Format.R32Uscaled:
- case Format.R32Sscaled:
- case Format.R32G32Uscaled:
- case Format.R32G32Sscaled:
- case Format.R32G32B32Uscaled:
- case Format.R32G32B32Sscaled:
- case Format.R32G32B32A32Uscaled:
- case Format.R32G32B32A32Sscaled:
- case Format.R10G10B10A2Snorm:
- case Format.R10G10B10A2Sint:
- case Format.R10G10B10A2Uscaled:
- case Format.R10G10B10A2Sscaled:
- case Format.B10G10R10A2Unorm:
- return 4;
+ ///
+ /// Checks if the texture format is a stencil or depth-stencil format.
+ ///
+ public bool HasStencil => fmt is
+ Format.D24UnormS8Uint or Format.S8UintD24Unorm or Format.D32FloatS8Uint or Format.S8Uint;
- case Format.S8Uint:
- return 1;
- case Format.D16Unorm:
- return 2;
- case Format.S8UintD24Unorm:
- case Format.X8UintD24Unorm:
- case Format.D32Float:
- case Format.D24UnormS8Uint:
- return 4;
- case Format.D32FloatS8Uint:
- return 8;
+ ///
+ /// Checks if the texture format is valid to use as image format.
+ ///
+ public bool IsImageCompatible => fmt is
+ Format.R8Unorm or Format.R8Snorm or Format.R8Uint or Format.R8Sint or Format.R16Float or Format.R16Unorm
+ or Format.R16Snorm or Format.R16Uint or Format.R16Sint or Format.R32Float or Format.R32Uint
+ or Format.R32Sint or Format.R8G8Unorm or Format.R8G8Snorm or Format.R8G8Uint or Format.R8G8Sint
+ or Format.R16G16Float or Format.R16G16Unorm or Format.R16G16Snorm or Format.R16G16Uint
+ or Format.R16G16Sint or Format.R32G32Float or Format.R32G32Uint or Format.R32G32Sint
+ or Format.R8G8B8A8Unorm or Format.R8G8B8A8Snorm or Format.R8G8B8A8Uint or Format.R8G8B8A8Sint
+ or Format.R16G16B16A16Float or Format.R16G16B16A16Unorm or Format.R16G16B16A16Snorm
+ or Format.R16G16B16A16Uint or Format.R16G16B16A16Sint or Format.R32G32B32A32Float
+ or Format.R32G32B32A32Uint or Format.R32G32B32A32Sint or Format.R10G10B10A2Unorm
+ or Format.R10G10B10A2Uint or Format.R11G11B10Float or Format.B8G8R8A8Unorm;
- case Format.Bc1RgbaUnorm:
- case Format.Bc1RgbaSrgb:
- return 8;
+ ///
+ /// Checks if the texture format is valid to use as render target color format.
+ ///
+ public bool IsRtColorCompatible => fmt is
+ Format.R32G32B32A32Float or Format.R32G32B32A32Sint or Format.R32G32B32A32Uint
+ or Format.R16G16B16A16Unorm or Format.R16G16B16A16Snorm or Format.R16G16B16A16Sint
+ or Format.R16G16B16A16Uint or Format.R16G16B16A16Float or Format.R32G32Float or Format.R32G32Sint
+ or Format.R32G32Uint or Format.B8G8R8A8Unorm or Format.B8G8R8A8Srgb or Format.B10G10R10A2Unorm
+ or Format.R10G10B10A2Unorm or Format.R10G10B10A2Uint or Format.R8G8B8A8Unorm or Format.R8G8B8A8Srgb
+ or Format.R8G8B8A8Snorm or Format.R8G8B8A8Sint or Format.R8G8B8A8Uint or Format.R16G16Unorm
+ or Format.R16G16Snorm or Format.R16G16Sint or Format.R16G16Uint or Format.R16G16Float
+ or Format.R11G11B10Float or Format.R32Sint or Format.R32Uint or Format.R32Float
+ or Format.B5G6R5Unorm or Format.B5G5R5A1Unorm or Format.R8G8Unorm or Format.R8G8Snorm
+ or Format.R8G8Sint or Format.R8G8Uint or Format.R16Unorm or Format.R16Snorm or Format.R16Sint
+ or Format.R16Uint or Format.R16Float or Format.R8Unorm or Format.R8Snorm or Format.R8Sint
+ or Format.R8Uint;
- case Format.Bc2Unorm:
- case Format.Bc3Unorm:
- case Format.Bc2Srgb:
- case Format.Bc3Srgb:
- case Format.Bc4Unorm:
- case Format.Bc4Snorm:
- case Format.Bc5Unorm:
- case Format.Bc5Snorm:
- case Format.Bc7Unorm:
- case Format.Bc7Srgb:
- case Format.Bc6HSfloat:
- case Format.Bc6HUfloat:
- return 16;
+ ///
+ /// Checks if the texture format is 16 bit packed.
+ ///
+ public bool Is16BitPacked => fmt is
+ Format.B5G6R5Unorm or Format.B5G5R5A1Unorm or Format.R5G5B5X1Unorm or Format.R5G5B5A1Unorm
+ or Format.R5G6B5Unorm or Format.R4G4B4A4Unorm;
- case Format.Etc2RgbUnorm:
- case Format.Etc2RgbPtaUnorm:
- case Format.Etc2RgbSrgb:
- case Format.Etc2RgbPtaSrgb:
- return 8;
+ ///
+ /// Checks if the texture format is an ETC2 format.
+ ///
+ public bool IsEtc2 => fmt is
+ Format.Etc2RgbaSrgb or Format.Etc2RgbaUnorm or Format.Etc2RgbPtaSrgb
+ or Format.Etc2RgbPtaUnorm or Format.Etc2RgbSrgb or Format.Etc2RgbUnorm;
- case Format.Etc2RgbaUnorm:
- case Format.Etc2RgbaSrgb:
- return 16;
+ ///
+ /// Checks if the texture format is a BGR format.
+ ///
+ public bool IsBgr => fmt is
+ Format.B5G6R5Unorm or Format.B5G5R5A1Unorm or Format.B8G8R8A8Unorm or Format.B8G8R8A8Srgb
+ or Format.B10G10R10A2Unorm;
- case Format.Astc4x4Unorm:
- case Format.Astc5x4Unorm:
- case Format.Astc5x5Unorm:
- case Format.Astc6x5Unorm:
- case Format.Astc6x6Unorm:
- case Format.Astc8x5Unorm:
- case Format.Astc8x6Unorm:
- case Format.Astc8x8Unorm:
- case Format.Astc10x5Unorm:
- case Format.Astc10x6Unorm:
- case Format.Astc10x8Unorm:
- case Format.Astc10x10Unorm:
- case Format.Astc12x10Unorm:
- case Format.Astc12x12Unorm:
- case Format.Astc4x4Srgb:
- case Format.Astc5x4Srgb:
- case Format.Astc5x5Srgb:
- case Format.Astc6x5Srgb:
- case Format.Astc6x6Srgb:
- case Format.Astc8x5Srgb:
- case Format.Astc8x6Srgb:
- case Format.Astc8x8Srgb:
- case Format.Astc10x5Srgb:
- case Format.Astc10x6Srgb:
- case Format.Astc10x8Srgb:
- case Format.Astc10x10Srgb:
- case Format.Astc12x10Srgb:
- case Format.Astc12x12Srgb:
- return 16;
- }
+ ///
+ /// Checks if the texture format is a depth, stencil or depth-stencil format.
+ ///
+ public bool IsDepthOrStencil => fmt is
+ Format.D16Unorm or Format.D24UnormS8Uint or Format.S8UintD24Unorm or Format.X8UintD24Unorm
+ or Format.D32Float or Format.D32FloatS8Uint or Format.S8Uint;
- return 1;
- }
+ ///
+ /// Checks if the texture format is a float or sRGB color format.
+ ///
+ ///
+ /// Does not include normalized, compressed or depth formats.
+ /// Float and sRGB formats do not participate in logical operations.
+ ///
+ public bool IsFloatOrSrgb => fmt is
+ Format.R8G8B8A8Srgb or Format.B8G8R8A8Srgb or Format.R16Float or Format.R16G16Float
+ or Format.R16G16B16Float or Format.R16G16B16A16Float or Format.R32Float or Format.R32G32Float
+ or Format.R32G32B32Float or Format.R32G32B32A32Float or Format.R11G11B10Float
+ or Format.R9G9B9E5Float;
+
+ ///
+ /// Checks if the texture format is an ASTC Unorm format.
+ ///
+ public bool IsAstcUnorm => fmt is
+ Format.Astc4x4Unorm or Format.Astc5x4Unorm or Format.Astc5x5Unorm or Format.Astc6x5Unorm
+ or Format.Astc6x6Unorm or Format.Astc8x5Unorm or Format.Astc8x6Unorm or Format.Astc8x8Unorm
+ or Format.Astc10x5Unorm or Format.Astc10x6Unorm or Format.Astc10x8Unorm or Format.Astc10x10Unorm
+ or Format.Astc12x10Unorm or Format.Astc12x12Unorm;
- ///
- /// Checks if the texture format is a depth or depth-stencil format.
- ///
- /// Texture format
- /// True if the format is a depth or depth-stencil format, false otherwise
- public static bool HasDepth(this Format format)
- {
- switch (format)
- {
- case Format.D16Unorm:
- case Format.D24UnormS8Uint:
- case Format.S8UintD24Unorm:
- case Format.X8UintD24Unorm:
- case Format.D32Float:
- case Format.D32FloatS8Uint:
- return true;
- }
+ ///
+ /// Checks if the texture format is an ASTC SRGB format.
+ ///
+ public bool IsAstcSrgb => fmt is
+ Format.Astc4x4Srgb or Format.Astc5x4Srgb or Format.Astc5x5Srgb or Format.Astc6x5Srgb
+ or Format.Astc6x6Srgb or Format.Astc8x5Srgb or Format.Astc8x6Srgb or Format.Astc8x8Srgb
+ or Format.Astc10x5Srgb or Format.Astc10x6Srgb or Format.Astc10x8Srgb or Format.Astc10x10Srgb
+ or Format.Astc12x10Srgb or Format.Astc12x12Srgb;
- return false;
- }
+ ///
+ /// Checks if the texture format is an ASTC format.
+ ///
+ public bool IsAstc => fmt.IsAstcUnorm || fmt.IsAstcSrgb;
- ///
- /// Checks if the texture format is a stencil or depth-stencil format.
- ///
- /// Texture format
- /// True if the format is a stencil or depth-stencil format, false otherwise
- public static bool HasStencil(this Format format)
- {
- switch (format)
- {
- case Format.D24UnormS8Uint:
- case Format.S8UintD24Unorm:
- case Format.D32FloatS8Uint:
- case Format.S8Uint:
- return true;
- }
+ ///
+ /// Checks if the texture format is an unsigned integer color format.
+ ///
+ public bool IsUnsignedInt => fmt is
+ Format.R8Uint or Format.R16Uint or Format.R32Uint or Format.R8G8Uint or Format.R16G16Uint
+ or Format.R32G32Uint or Format.R8G8B8Uint or Format.R16G16B16Uint or Format.R32G32B32Uint
+ or Format.R8G8B8A8Uint or Format.R16G16B16A16Uint or Format.R32G32B32A32Uint
+ or Format.R10G10B10A2Uint;
- return false;
- }
+ ///
+ /// Checks if the texture format is a signed integer color format.
+ ///
+ public bool IsSignedInt => fmt is
+ Format.R8Sint or Format.R16Sint or Format.R32Sint or Format.R8G8Sint or Format.R16G16Sint
+ or Format.R32G32Sint or Format.R8G8B8Sint or Format.R16G16B16Sint or Format.R32G32B32Sint
+ or Format.R8G8B8A8Sint or Format.R16G16B16A16Sint or Format.R32G32B32A32Sint
+ or Format.R10G10B10A2Sint;
- ///
- /// Checks if the texture format is valid to use as image format.
- ///
- /// Texture format
- /// True if the texture can be used as image, false otherwise
- public static bool IsImageCompatible(this Format format)
- {
- switch (format)
- {
- case Format.R8Unorm:
- case Format.R8Snorm:
- case Format.R8Uint:
- case Format.R8Sint:
- case Format.R16Float:
- case Format.R16Unorm:
- case Format.R16Snorm:
- case Format.R16Uint:
- case Format.R16Sint:
- case Format.R32Float:
- case Format.R32Uint:
- case Format.R32Sint:
- case Format.R8G8Unorm:
- case Format.R8G8Snorm:
- case Format.R8G8Uint:
- case Format.R8G8Sint:
- case Format.R16G16Float:
- case Format.R16G16Unorm:
- case Format.R16G16Snorm:
- case Format.R16G16Uint:
- case Format.R16G16Sint:
- case Format.R32G32Float:
- case Format.R32G32Uint:
- case Format.R32G32Sint:
- case Format.R8G8B8A8Unorm:
- case Format.R8G8B8A8Snorm:
- case Format.R8G8B8A8Uint:
- case Format.R8G8B8A8Sint:
- case Format.R16G16B16A16Float:
- case Format.R16G16B16A16Unorm:
- case Format.R16G16B16A16Snorm:
- case Format.R16G16B16A16Uint:
- case Format.R16G16B16A16Sint:
- case Format.R32G32B32A32Float:
- case Format.R32G32B32A32Uint:
- case Format.R32G32B32A32Sint:
- case Format.R10G10B10A2Unorm:
- case Format.R10G10B10A2Uint:
- case Format.R11G11B10Float:
- case Format.B8G8R8A8Unorm:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is valid to use as render target color format.
- ///
- /// Texture format
- /// True if the texture can be used as render target, false otherwise
- public static bool IsRtColorCompatible(this Format format)
- {
- switch (format)
- {
- case Format.R32G32B32A32Float:
- case Format.R32G32B32A32Sint:
- case Format.R32G32B32A32Uint:
- case Format.R16G16B16A16Unorm:
- case Format.R16G16B16A16Snorm:
- case Format.R16G16B16A16Sint:
- case Format.R16G16B16A16Uint:
- case Format.R16G16B16A16Float:
- case Format.R32G32Float:
- case Format.R32G32Sint:
- case Format.R32G32Uint:
- case Format.B8G8R8A8Unorm:
- case Format.B8G8R8A8Srgb:
- case Format.B10G10R10A2Unorm:
- case Format.R10G10B10A2Unorm:
- case Format.R10G10B10A2Uint:
- case Format.R8G8B8A8Unorm:
- case Format.R8G8B8A8Srgb:
- case Format.R8G8B8A8Snorm:
- case Format.R8G8B8A8Sint:
- case Format.R8G8B8A8Uint:
- case Format.R16G16Unorm:
- case Format.R16G16Snorm:
- case Format.R16G16Sint:
- case Format.R16G16Uint:
- case Format.R16G16Float:
- case Format.R11G11B10Float:
- case Format.R32Sint:
- case Format.R32Uint:
- case Format.R32Float:
- case Format.B5G6R5Unorm:
- case Format.B5G5R5A1Unorm:
- case Format.R8G8Unorm:
- case Format.R8G8Snorm:
- case Format.R8G8Sint:
- case Format.R8G8Uint:
- case Format.R16Unorm:
- case Format.R16Snorm:
- case Format.R16Sint:
- case Format.R16Uint:
- case Format.R16Float:
- case Format.R8Unorm:
- case Format.R8Snorm:
- case Format.R8Sint:
- case Format.R8Uint:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is 16 bit packed.
- ///
- /// Texture format
- /// True if the texture format is 16 bit packed, false otherwise
- public static bool Is16BitPacked(this Format format)
- {
- switch (format)
- {
- case Format.B5G6R5Unorm:
- case Format.B5G5R5A1Unorm:
- case Format.R5G5B5X1Unorm:
- case Format.R5G5B5A1Unorm:
- case Format.R5G6B5Unorm:
- case Format.R4G4B4A4Unorm:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is an ASTC format.
- ///
- /// Texture format
- /// True if the texture format is an ASTC format, false otherwise
- public static bool IsAstc(this Format format)
- {
- return format.IsAstcUnorm() || format.IsAstcSrgb();
- }
-
- ///
- /// Checks if the texture format is an ASTC Unorm format.
- ///
- /// Texture format
- /// True if the texture format is an ASTC Unorm format, false otherwise
- public static bool IsAstcUnorm(this Format format)
- {
- switch (format)
- {
- case Format.Astc4x4Unorm:
- case Format.Astc5x4Unorm:
- case Format.Astc5x5Unorm:
- case Format.Astc6x5Unorm:
- case Format.Astc6x6Unorm:
- case Format.Astc8x5Unorm:
- case Format.Astc8x6Unorm:
- case Format.Astc8x8Unorm:
- case Format.Astc10x5Unorm:
- case Format.Astc10x6Unorm:
- case Format.Astc10x8Unorm:
- case Format.Astc10x10Unorm:
- case Format.Astc12x10Unorm:
- case Format.Astc12x12Unorm:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is an ASTC SRGB format.
- ///
- /// Texture format
- /// True if the texture format is an ASTC SRGB format, false otherwise
- public static bool IsAstcSrgb(this Format format)
- {
- switch (format)
- {
- case Format.Astc4x4Srgb:
- case Format.Astc5x4Srgb:
- case Format.Astc5x5Srgb:
- case Format.Astc6x5Srgb:
- case Format.Astc6x6Srgb:
- case Format.Astc8x5Srgb:
- case Format.Astc8x6Srgb:
- case Format.Astc8x8Srgb:
- case Format.Astc10x5Srgb:
- case Format.Astc10x6Srgb:
- case Format.Astc10x8Srgb:
- case Format.Astc10x10Srgb:
- case Format.Astc12x10Srgb:
- case Format.Astc12x12Srgb:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is an ETC2 format.
- ///
- /// Texture format
- /// True if the texture format is an ETC2 format, false otherwise
- public static bool IsEtc2(this Format format)
- {
- switch (format)
- {
- case Format.Etc2RgbaSrgb:
- case Format.Etc2RgbaUnorm:
- case Format.Etc2RgbPtaSrgb:
- case Format.Etc2RgbPtaUnorm:
- case Format.Etc2RgbSrgb:
- case Format.Etc2RgbUnorm:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is a BGR format.
- ///
- /// Texture format
- /// True if the texture format is a BGR format, false otherwise
- public static bool IsBgr(this Format format)
- {
- switch (format)
- {
- case Format.B5G6R5Unorm:
- case Format.B5G5R5A1Unorm:
- case Format.B8G8R8A8Unorm:
- case Format.B8G8R8A8Srgb:
- case Format.B10G10R10A2Unorm:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is a depth, stencil or depth-stencil format.
- ///
- /// Texture format
- /// True if the format is a depth, stencil or depth-stencil format, false otherwise
- public static bool IsDepthOrStencil(this Format format)
- {
- switch (format)
- {
- case Format.D16Unorm:
- case Format.D24UnormS8Uint:
- case Format.S8UintD24Unorm:
- case Format.X8UintD24Unorm:
- case Format.D32Float:
- case Format.D32FloatS8Uint:
- case Format.S8Uint:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is an unsigned integer color format.
- ///
- /// Texture format
- /// True if the texture format is an unsigned integer color format, false otherwise
- public static bool IsUint(this Format format)
- {
- switch (format)
- {
- case Format.R8Uint:
- case Format.R16Uint:
- case Format.R32Uint:
- case Format.R8G8Uint:
- case Format.R16G16Uint:
- case Format.R32G32Uint:
- case Format.R8G8B8Uint:
- case Format.R16G16B16Uint:
- case Format.R32G32B32Uint:
- case Format.R8G8B8A8Uint:
- case Format.R16G16B16A16Uint:
- case Format.R32G32B32A32Uint:
- case Format.R10G10B10A2Uint:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is a signed integer color format.
- ///
- /// Texture format
- /// True if the texture format is a signed integer color format, false otherwise
- public static bool IsSint(this Format format)
- {
- switch (format)
- {
- case Format.R8Sint:
- case Format.R16Sint:
- case Format.R32Sint:
- case Format.R8G8Sint:
- case Format.R16G16Sint:
- case Format.R32G32Sint:
- case Format.R8G8B8Sint:
- case Format.R16G16B16Sint:
- case Format.R32G32B32Sint:
- case Format.R8G8B8A8Sint:
- case Format.R16G16B16A16Sint:
- case Format.R32G32B32A32Sint:
- case Format.R10G10B10A2Sint:
- return true;
- }
-
- return false;
- }
-
- ///
- /// Checks if the texture format is an integer color format.
- ///
- /// Texture format
- /// True if the texture format is an integer color format, false otherwise
- public static bool IsInteger(this Format format)
- {
- return format.IsUint() || format.IsSint();
- }
-
- ///
- /// Checks if the texture format is a float or sRGB color format.
- ///
- ///
- /// Does not include normalized, compressed or depth formats.
- /// Float and sRGB formats do not participate in logical operations.
- ///
- /// Texture format
- /// True if the format is a float or sRGB color format, false otherwise
- public static bool IsFloatOrSrgb(this Format format)
- {
- switch (format)
- {
- case Format.R8G8B8A8Srgb:
- case Format.B8G8R8A8Srgb:
- case Format.R16Float:
- case Format.R16G16Float:
- case Format.R16G16B16Float:
- case Format.R16G16B16A16Float:
- case Format.R32Float:
- case Format.R32G32Float:
- case Format.R32G32B32Float:
- case Format.R32G32B32A32Float:
- case Format.R11G11B10Float:
- case Format.R9G9B9E5Float:
- return true;
- }
-
- return false;
+ ///
+ /// Checks if the texture format is an integer color format.
+ ///
+ public bool IsInt => fmt.IsUnsignedInt || fmt.IsSignedInt;
}
}
}
diff --git a/src/Ryujinx.Graphics.GAL/Target.cs b/src/Ryujinx.Graphics.GAL/Target.cs
index 1c184981d..531051d02 100644
--- a/src/Ryujinx.Graphics.GAL/Target.cs
+++ b/src/Ryujinx.Graphics.GAL/Target.cs
@@ -16,19 +16,18 @@ namespace Ryujinx.Graphics.GAL
public static class TargetExtensions
{
- public static bool IsMultisample(this Target target)
+ extension(Target target)
{
- return target is Target.Texture2DMultisample or Target.Texture2DMultisampleArray;
- }
+ public bool IsMultisample => target is Target.Texture2DMultisample or Target.Texture2DMultisampleArray;
- public static bool HasDepthOrLayers(this Target target)
- {
- return target is Target.Texture3D or
- Target.Texture1DArray or
- Target.Texture2DArray or
- Target.Texture2DMultisampleArray or
- Target.Cubemap or
- Target.CubemapArray;
+ public bool HasDepthOrLayers =>
+ target is
+ Target.Texture3D or
+ Target.Texture1DArray or
+ Target.Texture2DArray or
+ Target.Texture2DMultisampleArray or
+ Target.Cubemap or
+ Target.CubemapArray;
}
}
}
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
index 37d7457fc..c9fe2470e 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
@@ -171,7 +171,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
{
MemoryManager memoryManager = _channel.MemoryManager;
- Span data = MemoryMarshal.Cast(_buffer)[.._size];
+ Span data = MemoryMarshal.Cast(new Span(_buffer))[.._size];
if (_isLinear && _lineCount == 1)
{
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs
index 23a73908d..6d62464d2 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs
@@ -176,7 +176,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
ulong vbSize = GetVertexBufferSize(address, endAddress.Pack(), vbStride, _indexed, instanced, _firstVertex, _count);
ulong attributeOffset = (ulong)vertexAttrib.UnpackOffset();
- int componentSize = format.GetScalarSize();
+ int componentSize = format.ScalarSize;
address += attributeOffset;
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
index f97f80251..d9218e524 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
@@ -849,8 +849,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FormatInfo dsFormat = _state.State.RtDepthStencilState.Format.Convert();
- bool hasDepth = dsFormat.Format.HasDepth();
- bool hasStencil = dsFormat.Format.HasStencil();
+ bool hasDepth = dsFormat.Format.HasDepth;
+ bool hasStencil = dsFormat.Format.HasStencil;
if (hasStencil && (!clearStencil || (clearAffectedByStencilMask && _state.State.StencilTestState.FrontMask != 0xff)))
{
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
index 2fb8de920..0c1e33731 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
@@ -297,7 +297,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
Format format = colorState.Format.Convert().Format;
- AttributeType type = format.IsInteger() ? (format.IsSint() ? AttributeType.Sint : AttributeType.Uint) : AttributeType.Float;
+ AttributeType type = format.IsInt
+ ? (format.IsSignedInt ? AttributeType.Sint : AttributeType.Uint)
+ : AttributeType.Float;
if (type != fragmentOutputTypesSpan[index])
{
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index fe57c05ee..4f2f01606 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -534,7 +534,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (!_context.Capabilities.SupportsBgraFormat)
{
- _context.SupportBufferUpdater.SetRenderTargetIsBgra(index, color.Format.IsBgr());
+ _context.SupportBufferUpdater.SetRenderTargetIsBgra(index, color.Format.IsBgr);
}
}
}
@@ -1317,10 +1317,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FilterBlendFactor(blend.AlphaDstFactor, index));
if (enable &&
- (blend.ColorSrcFactor.IsDualSource() ||
- blend.ColorDstFactor.IsDualSource() ||
- blend.AlphaSrcFactor.IsDualSource() ||
- blend.AlphaDstFactor.IsDualSource()))
+ (blend.ColorSrcFactor.IsDualSource ||
+ blend.ColorDstFactor.IsDualSource ||
+ blend.AlphaSrcFactor.IsDualSource ||
+ blend.AlphaDstFactor.IsDualSource))
{
dualSourceBlendEnabled = true;
}
@@ -1345,10 +1345,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FilterBlendFactor(blend.AlphaDstFactor, 0));
if (enable &&
- (blend.ColorSrcFactor.IsDualSource() ||
- blend.ColorDstFactor.IsDualSource() ||
- blend.AlphaSrcFactor.IsDualSource() ||
- blend.AlphaDstFactor.IsDualSource()))
+ (blend.ColorSrcFactor.IsDualSource ||
+ blend.ColorDstFactor.IsDualSource ||
+ blend.AlphaSrcFactor.IsDualSource ||
+ blend.AlphaDstFactor.IsDualSource))
{
dualSourceBlendEnabled = true;
}
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs
index 5ab58d7d1..5deddbadf 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs
@@ -333,7 +333,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod
// as copies between depth and color formats are not allowed.
// For depth blit, the destination texture format should always match exactly.
- if (srcTexture.Format.IsDepthOrStencil())
+ if (srcTexture.Format.IsDepthOrStencil)
{
dstCopyTextureFormat = srcTexture.Info.FormatInfo;
}
diff --git a/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs b/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs
index 8bfebe8a1..b1e46cfbe 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/FormatTable.cs
@@ -662,7 +662,7 @@ namespace Ryujinx.Graphics.Gpu.Image
bool found = _textureFormats.TryGetValue((TextureFormat)encoded, out format);
- if (found && isPacked && !format.Format.IsDepthOrStencil())
+ if (found && isPacked && !format.Format.IsDepthOrStencil)
{
// If the packed flag is set, then the components of the pixel are tightly packed into the
// GPU registers on the shader.
diff --git a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs
index 35fc38d0b..05a316c45 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -643,7 +643,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// The decompression is slow, so we want to avoid it as much as possible.
// This does a byte-by-byte check and skips the update if the data is equal in this case.
// This improves the speed on applications that overwrites ASTC data without changing anything.
- if (Info.FormatInfo.Format.IsAstc() && !_context.Capabilities.SupportsAstcCompression)
+ if (Info.FormatInfo.Format.IsAstc && !_context.Capabilities.SupportsAstcCompression)
{
if (_updateCount < ByteComparisonSwitchThreshold)
{
@@ -792,7 +792,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// Handle compressed cases not supported by the host:
// - ASTC is usually not supported on desktop cards.
// - BC4/BC5 is not supported on 3D textures.
- if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc())
+ if (!_context.Capabilities.SupportsAstcCompression && Format.IsAstc)
{
using (result)
{
@@ -823,7 +823,7 @@ namespace Ryujinx.Graphics.Gpu.Image
return decoded;
}
}
- else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2())
+ else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2)
{
switch (Format)
{
@@ -924,7 +924,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
}
- else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked())
+ else if (!_context.Capabilities.Supports5BitComponentFormat && Format.Is16BitPacked)
{
switch (Format)
{
@@ -1251,7 +1251,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info, ref caps));
- bool bothMs = Info.Target.IsMultisample() && info.Target.IsMultisample();
+ bool bothMs = Info.Target.IsMultisample && info.Target.IsMultisample;
if (bothMs && (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY))
{
result = TextureViewCompatibility.Incompatible;
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index f3df8b072..390d7c5c7 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -180,7 +180,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int widthAlignment = (info.IsLinear ? Constants.StrideAlignment : Constants.GobAlignment) / info.FormatInfo.BytesPerPixel;
- if (!(info.FormatInfo.Format.IsDepthOrStencil() || info.FormatInfo.Components == 1))
+ if (!(info.FormatInfo.Format.IsDepthOrStencil || info.FormatInfo.Components == 1))
{
// Discount square textures that aren't depth-stencil like. (excludes game textures, cubemap faces, most 3D texture LUT, texture atlas)
// Detect if the texture is possibly square. Widths may be aligned, so to remove the uncertainty we align both the width and height.
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
index f2cbca832..af7e9a7af 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
@@ -75,13 +75,14 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!caps.SupportsAstcCompression)
{
- if (info.FormatInfo.Format.IsAstcUnorm())
+ if (info.FormatInfo.Format.IsAstcUnorm)
{
return GraphicsConfig.EnableTextureRecompression
? new FormatInfo(Format.Bc7Unorm, 4, 4, 16, 4)
: new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
}
- else if (info.FormatInfo.Format.IsAstcSrgb())
+
+ if (info.FormatInfo.Format.IsAstcSrgb)
{
return GraphicsConfig.EnableTextureRecompression
? new FormatInfo(Format.Bc7Srgb, 4, 4, 16, 4)
@@ -151,9 +152,9 @@ namespace Ryujinx.Graphics.Gpu.Image
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
}
}
- else if (!caps.Supports5BitComponentFormat && info.FormatInfo.Format.Is16BitPacked())
+ else if (!caps.Supports5BitComponentFormat && info.FormatInfo.Format.Is16BitPacked)
{
- return new FormatInfo(info.FormatInfo.Format.IsBgr() ? Format.B8G8R8A8Unorm : Format.R8G8B8A8Unorm, 1, 1, 4, 4);
+ return new FormatInfo(info.FormatInfo.Format.IsBgr ? Format.B8G8R8A8Unorm : Format.R8G8B8A8Unorm, 1, 1, 4, 4);
}
return info.FormatInfo;
@@ -388,7 +389,7 @@ namespace Ryujinx.Graphics.Gpu.Image
return stride == rhs.Stride ? TextureViewCompatibility.CopyOnly : TextureViewCompatibility.LayoutIncompatible;
}
- else if (lhs.Target.IsMultisample() != rhs.Target.IsMultisample() && alignedWidthMatches && lhsAlignedSize.Height == rhsAlignedSize.Height)
+ else if (lhs.Target.IsMultisample != rhs.Target.IsMultisample && alignedWidthMatches && lhsAlignedSize.Height == rhsAlignedSize.Height)
{
// Copy between multisample and non-multisample textures with mismatching size is allowed,
// as long aligned size matches.
@@ -644,7 +645,7 @@ namespace Ryujinx.Graphics.Gpu.Image
FormatInfo lhsFormat = lhs.FormatInfo;
FormatInfo rhsFormat = rhs.FormatInfo;
- if (lhsFormat.Format.IsDepthOrStencil() || rhsFormat.Format.IsDepthOrStencil())
+ if (lhsFormat.Format.IsDepthOrStencil || rhsFormat.Format.IsDepthOrStencil)
{
bool forSampler = flags.HasFlag(TextureSearchFlags.ForSampler);
bool depthAlias = flags.HasFlag(TextureSearchFlags.DepthAlias);
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
index 8865c46cc..e7a1afe1a 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs
@@ -147,7 +147,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_allOffsets = size.AllOffsets;
_sliceSizes = size.SliceSizes;
- if (Storage.Target.HasDepthOrLayers() && Storage.Info.GetSlices() > GranularLayerThreshold)
+ if (Storage.Target.HasDepthOrLayers && Storage.Info.GetSlices() > GranularLayerThreshold)
{
_hasLayerViews = true;
_hasMipViews = true;
diff --git a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index c2a503840..d9fe02f8d 100644
--- a/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/src/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -660,7 +660,7 @@ namespace Ryujinx.Graphics.Gpu.Image
swizzleB,
swizzleA);
- if (formatInfo.Format.IsDepthOrStencil())
+ if (formatInfo.Format.IsDepthOrStencil)
{
swizzleR = SwizzleComponent.Red;
swizzleG = SwizzleComponent.Red;
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs b/src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
index 7861eb4fe..277a30689 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
@@ -138,7 +138,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{
if (item.Value._useGranular)
{
- baseHandles.AddRange((item.Value._memoryTrackingGranular.GetHandles()));
+ baseHandles.AddRange(item.Value._memoryTrackingGranular.Handles);
}
else
{
diff --git a/src/Ryujinx.Graphics.OpenGL/Buffer.cs b/src/Ryujinx.Graphics.OpenGL/Buffer.cs
index 33ca25174..9df408944 100644
--- a/src/Ryujinx.Graphics.OpenGL/Buffer.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Buffer.cs
@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.OpenGL
{
public static void Clear(BufferHandle destination, int offset, int size, uint value)
{
- GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination.ToInt32());
+ GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination);
unsafe
{
@@ -58,8 +58,8 @@ namespace Ryujinx.Graphics.OpenGL
public static void Copy(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
{
- GL.BindBuffer(BufferTarget.CopyReadBuffer, source.ToInt32());
- GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination.ToInt32());
+ GL.BindBuffer(BufferTarget.CopyReadBuffer, source);
+ GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination);
GL.CopyBufferSubData(
BufferTarget.CopyReadBuffer,
@@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.OpenGL
{
nint target = renderer.PersistentBuffers.Default.GetHostArray(size);
- GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer.ToInt32());
+ GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer);
GL.GetBufferSubData(BufferTarget.CopyReadBuffer, (nint)offset, size, target);
@@ -96,13 +96,13 @@ namespace Ryujinx.Graphics.OpenGL
public static void Resize(BufferHandle handle, int size)
{
- GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle.ToInt32());
+ GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle);
GL.BufferData(BufferTarget.CopyWriteBuffer, size, nint.Zero, BufferUsageHint.StreamCopy);
}
public static void SetData(BufferHandle buffer, int offset, ReadOnlySpan data)
{
- GL.BindBuffer(BufferTarget.CopyWriteBuffer, buffer.ToInt32());
+ GL.BindBuffer(BufferTarget.CopyWriteBuffer, buffer);
unsafe
{
@@ -115,7 +115,7 @@ namespace Ryujinx.Graphics.OpenGL
public static void Delete(BufferHandle buffer)
{
- GL.DeleteBuffer(buffer.ToInt32());
+ GL.DeleteBuffer(buffer);
}
}
}
diff --git a/src/Ryujinx.Graphics.OpenGL/Handle.cs b/src/Ryujinx.Graphics.OpenGL/Handle.cs
index b63e8f946..3803f0b07 100644
--- a/src/Ryujinx.Graphics.OpenGL/Handle.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Handle.cs
@@ -1,4 +1,3 @@
-using Ryujinx.Graphics.GAL;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@@ -14,10 +13,5 @@ namespace Ryujinx.Graphics.OpenGL
return Unsafe.As(ref handle64);
}
-
- public static int ToInt32(this BufferHandle handle)
- {
- return (int)Unsafe.As(ref handle);
- }
}
}
diff --git a/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs b/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs
index 64e4fe36d..1a67c28e7 100644
--- a/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Image/FormatConverter.cs
@@ -139,7 +139,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
start = sizeAligned;
}
- Span outSpan = MemoryMarshal.Cast(output);
+ Span outSpan = MemoryMarshal.Cast(new Span(output));
ReadOnlySpan dataSpan = MemoryMarshal.Cast(data);
for (int i = start / sizeof(uint); i < dataSpan.Length; i++)
{
diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
index 231d9c97b..9ad4eb824 100644
--- a/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
@@ -97,7 +97,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
SizedInternalFormat format = (SizedInternalFormat)FormatTable.GetFormatInfo(Info.Format).PixelInternalFormat;
- GL.TexBufferRange(TextureBufferTarget.TextureBuffer, format, _buffer.ToInt32(), (nint)buffer.Offset, buffer.Size);
+ GL.TexBufferRange(TextureBufferTarget.TextureBuffer, format, _buffer, (nint)buffer.Offset, buffer.Size);
}
public void Dispose()
diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs
index 3d1e47339..4b6821934 100644
--- a/src/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs
@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
int layers,
int levels)
{
- TextureView srcConverted = src.Format.IsBgr() != dst.Format.IsBgr() ? BgraSwap(src) : src;
+ TextureView srcConverted = src.Format.IsBgr != dst.Format.IsBgr ? BgraSwap(src) : src;
(int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();
@@ -87,7 +87,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
ClearBufferMask mask = GetMask(src.Format);
- if ((mask & (ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit)) != 0 || src.Format.IsInteger())
+ if ((mask & (ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit)) != 0 || src.Format.IsInt)
{
linearFilter = false;
}
diff --git a/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs b/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
index fcd004dd6..12ec23c8b 100644
--- a/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
@@ -84,7 +84,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
swizzleRgba[2] = temp2;
swizzleRgba[3] = temp;
}
- else if (Info.Format.IsBgr())
+ else if (Info.Format.IsBgr)
{
// Swap B <-> R for BGRA formats, as OpenGL has no support for them
// and we need to manually swap the components on read/write on the GPU.
@@ -116,13 +116,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
TextureView destinationView = (TextureView)destination;
- bool srcIsMultisample = Target.IsMultisample();
- bool dstIsMultisample = destinationView.Target.IsMultisample();
+ bool srcIsMultisample = Target.IsMultisample;
+ bool dstIsMultisample = destinationView.Target.IsMultisample;
- if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil())
+ if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil)
{
int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
- CopyWithBlitForDepthMS(destinationView, 0, firstLayer, layers);
+ CopyWithBlitForDepthMultisample(destinationView, 0, firstLayer, layers);
}
else if (!dstIsMultisample && srcIsMultisample)
{
@@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
int levels = Math.Min(Info.Levels, destinationView.Info.Levels - firstLevel);
_renderer.TextureCopyIncompatible.CopyIncompatibleFormats(this, destinationView, 0, firstLayer, 0, firstLevel, layers, levels);
}
- else if (destinationView.Format.IsDepthOrStencil() != Format.IsDepthOrStencil())
+ else if (destinationView.Format.IsDepthOrStencil != Format.IsDepthOrStencil)
{
int layers = Math.Min(Info.GetLayers(), destinationView.Info.GetLayers() - firstLayer);
int levels = Math.Min(Info.Levels, destinationView.Info.Levels - firstLevel);
@@ -172,12 +172,12 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
TextureView destinationView = (TextureView)destination;
- bool srcIsMultisample = Target.IsMultisample();
- bool dstIsMultisample = destinationView.Target.IsMultisample();
+ bool srcIsMultisample = Target.IsMultisample;
+ bool dstIsMultisample = destinationView.Target.IsMultisample;
- if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil())
+ if (dstIsMultisample != srcIsMultisample && Info.Format.IsDepthOrStencil)
{
- CopyWithBlitForDepthMS(destinationView, srcLayer, dstLayer, 1);
+ CopyWithBlitForDepthMultisample(destinationView, srcLayer, dstLayer, 1);
}
else if (!dstIsMultisample && srcIsMultisample)
{
@@ -191,7 +191,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
_renderer.TextureCopyIncompatible.CopyIncompatibleFormats(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
- else if (destinationView.Format.IsDepthOrStencil() != Format.IsDepthOrStencil())
+ else if (destinationView.Format.IsDepthOrStencil != Format.IsDepthOrStencil)
{
int minWidth = Math.Min(Width, destinationView.Width);
int minHeight = Math.Min(Height, destinationView.Height);
@@ -204,7 +204,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
}
- private void CopyWithBlitForDepthMS(TextureView destinationView, int srcLayer, int dstLayer, int layers)
+ private void CopyWithBlitForDepthMultisample(TextureView destinationView, int srcLayer, int dstLayer, int layers)
{
// This is currently used for multisample <-> non-multisample copies.
// We can't do that with compute because it's not possible to write depth textures on compute.
@@ -216,9 +216,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
Extents2D srcRegion = new(0, 0, Width, Height);
Extents2D dstRegion = new(0, 0, destinationView.Width, destinationView.Height);
- if (destinationView.Target.IsMultisample())
+ if (destinationView.Target.IsMultisample)
{
- TextureView intermmediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast(
+ TextureView intermediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast(
Info.Target,
Info.BlockWidth,
Info.BlockHeight,
@@ -230,8 +230,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
1,
1);
- _renderer.TextureCopy.Copy(this, intermmediate, srcRegion, dstRegion, false);
- _renderer.TextureCopy.Copy(intermmediate, destinationView, dstRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
+ _renderer.TextureCopy.Copy(this, intermediate, srcRegion, dstRegion, false);
+ _renderer.TextureCopy.Copy(intermediate, destinationView, dstRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
}
else
{
@@ -242,7 +242,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
_ => Target,
};
- TextureView intermmediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast(
+ TextureView intermediate = _renderer.TextureCopy.IntermediatePool.GetOrCreateWithAtLeast(
target,
Info.BlockWidth,
Info.BlockHeight,
@@ -254,8 +254,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
1,
1);
- _renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, false);
- _renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
+ _renderer.TextureCopy.Copy(this, intermediate, srcRegion, srcRegion, false);
+ _renderer.TextureCopy.Copy(intermediate, destinationView, srcRegion, dstRegion, false, srcLayer, dstLayer, 0, 0, layers, 1);
}
}
@@ -305,14 +305,12 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
return PinnedSpan.UnsafeFromSpan(_renderer.PersistentBuffers.Default.GetTextureData(this, size, layer, level));
}
- else
- {
- nint target = _renderer.PersistentBuffers.Default.GetHostArray(size);
- int offset = WriteTo2D(target, layer, level);
+ nint target = _renderer.PersistentBuffers.Default.GetHostArray(size);
- return new PinnedSpan((byte*)target.ToPointer() + offset, size);
- }
+ int offset = WriteTo2D(target, layer, level);
+
+ return new PinnedSpan((byte*)target.ToPointer() + offset, size);
}
public void CopyTo(BufferRange range, int layer, int level, int stride)
@@ -322,7 +320,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
throw new NotSupportedException("Stride conversion for texture copy to buffer not supported.");
}
- GL.BindBuffer(BufferTarget.PixelPackBuffer, range.Handle.ToInt32());
+ GL.BindBuffer(BufferTarget.PixelPackBuffer, range.Handle);
FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
if (format.PixelFormat == PixelFormat.DepthStencil)
diff --git a/src/Ryujinx.Graphics.OpenGL/PersistentBuffers.cs b/src/Ryujinx.Graphics.OpenGL/PersistentBuffers.cs
index 28ebe88a5..d5c02f4df 100644
--- a/src/Ryujinx.Graphics.OpenGL/PersistentBuffers.cs
+++ b/src/Ryujinx.Graphics.OpenGL/PersistentBuffers.cs
@@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.OpenGL
public void Map(BufferHandle handle, int size)
{
- GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle.ToInt32());
+ GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle);
nint ptr = GL.MapBufferRange(BufferTarget.CopyWriteBuffer, nint.Zero, size, BufferAccessMask.MapReadBit | BufferAccessMask.MapPersistentBit);
_maps[handle] = ptr;
@@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.OpenGL
{
if (_maps.ContainsKey(handle))
{
- GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle.ToInt32());
+ GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle);
GL.UnmapBuffer(BufferTarget.CopyWriteBuffer);
_maps.Remove(handle);
@@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.OpenGL
{
EnsureBuffer(size);
- GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer.ToInt32());
+ GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer);
GL.BindBuffer(BufferTarget.CopyWriteBuffer, _copyBufferHandle);
GL.CopyBufferSubData(BufferTarget.CopyReadBuffer, BufferTarget.CopyWriteBuffer, (nint)offset, nint.Zero, size);
diff --git a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 36db655ad..c8ca02140 100644
--- a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -587,7 +587,7 @@ namespace Ryujinx.Graphics.OpenGL
_vertexArray.SetRangeOfIndexBuffer();
- GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
+ GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle);
GL.DrawElementsIndirect(_primitiveType, _elementsType, (nint)indirectBuffer.Offset);
@@ -608,8 +608,8 @@ namespace Ryujinx.Graphics.OpenGL
_vertexArray.SetRangeOfIndexBuffer();
- GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
- GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
+ GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle);
+ GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle);
GL.MultiDrawElementsIndirectCount(
_primitiveType,
@@ -634,7 +634,7 @@ namespace Ryujinx.Graphics.OpenGL
PreDrawVbUnbounded();
- GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
+ GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle);
GL.DrawArraysIndirect(_primitiveType, (nint)indirectBuffer.Offset);
@@ -651,8 +651,8 @@ namespace Ryujinx.Graphics.OpenGL
PreDrawVbUnbounded();
- GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle.ToInt32());
- GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle.ToInt32());
+ GL.BindBuffer((BufferTarget)All.DrawIndirectBuffer, indirectBuffer.Handle);
+ GL.BindBuffer((BufferTarget)All.ParameterBuffer, parameterBuffer.Handle);
GL.MultiDrawArraysIndirectCount(
_primitiveType,
@@ -812,10 +812,10 @@ namespace Ryujinx.Graphics.OpenGL
EnsureFramebuffer();
_framebuffer.SetDualSourceBlend(
- blend.ColorSrcFactor.IsDualSource() ||
- blend.ColorDstFactor.IsDualSource() ||
- blend.AlphaSrcFactor.IsDualSource() ||
- blend.AlphaDstFactor.IsDualSource());
+ blend.ColorSrcFactor.IsDualSource ||
+ blend.ColorDstFactor.IsDualSource ||
+ blend.AlphaSrcFactor.IsDualSource ||
+ blend.AlphaDstFactor.IsDualSource);
if (_blendConstant != blend.BlendConstant)
{
@@ -1178,7 +1178,7 @@ namespace Ryujinx.Graphics.OpenGL
if (color != null)
{
- int isBgra = color.Format.IsBgr() ? 1 : 0;
+ int isBgra = color.Format.IsBgr ? 1 : 0;
if (_fpIsBgra[index].X != isBgra)
{
@@ -1349,7 +1349,7 @@ namespace Ryujinx.Graphics.OpenGL
Buffer.Resize(_tfbs[i], buffer.Size);
Buffer.Copy(buffer.Handle, _tfbs[i], buffer.Offset, 0, buffer.Size);
- GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, _tfbs[i].ToInt32());
+ GL.BindBufferBase(BufferRangeTarget.TransformFeedbackBuffer, i, _tfbs[i]);
}
if (_tfEnabled)
@@ -1454,7 +1454,7 @@ namespace Ryujinx.Graphics.OpenGL
continue;
}
- GL.BindBufferRange(target, assignment.Binding, buffer.Handle.ToInt32(), (nint)buffer.Offset, buffer.Size);
+ GL.BindBufferRange(target, assignment.Binding, buffer.Handle, (nint)buffer.Offset, buffer.Size);
}
}
diff --git a/src/Ryujinx.Graphics.OpenGL/VertexArray.cs b/src/Ryujinx.Graphics.OpenGL/VertexArray.cs
index 2480b6af2..f56a37c68 100644
--- a/src/Ryujinx.Graphics.OpenGL/VertexArray.cs
+++ b/src/Ryujinx.Graphics.OpenGL/VertexArray.cs
@@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.OpenGL
minVertexCount = vertexCount;
}
- GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle.ToInt32(), (nint)vb.Buffer.Offset, vb.Stride);
+ GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle, (nint)vb.Buffer.Offset, vb.Stride);
GL.VertexBindingDivisor(bindingIndex, vb.Divisor);
_vertexBuffersInUse |= 1u << bindingIndex;
}
@@ -134,19 +134,19 @@ namespace Ryujinx.Graphics.OpenGL
public void SetIndexBuffer(BufferRange range)
{
_indexBuffer = range;
- GL.BindBuffer(BufferTarget.ElementArrayBuffer, range.Handle.ToInt32());
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, range.Handle);
}
public void SetRangeOfIndexBuffer()
{
Buffer.Resize(_tempIndexBuffer, _indexBuffer.Size);
Buffer.Copy(_indexBuffer.Handle, _tempIndexBuffer, _indexBuffer.Offset, 0, _indexBuffer.Size);
- GL.BindBuffer(BufferTarget.ElementArrayBuffer, _tempIndexBuffer.ToInt32());
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, _tempIndexBuffer);
}
public void RestoreIndexBuffer()
{
- GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer.Handle.ToInt32());
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer.Handle);
}
public void PreDraw(int vertexCount)
@@ -188,7 +188,7 @@ namespace Ryujinx.Graphics.OpenGL
Buffer.Copy(vb.Buffer.Handle, tempVertexBuffer, vb.Buffer.Offset, currentTempVbOffset, vb.Buffer.Size);
Buffer.Clear(tempVertexBuffer, currentTempVbOffset + vb.Buffer.Size, requiredSize - vb.Buffer.Size, 0);
- GL.BindVertexBuffer(vbIndex, tempVertexBuffer.ToInt32(), (nint)currentTempVbOffset, vb.Stride);
+ GL.BindVertexBuffer(vbIndex, tempVertexBuffer, (nint)currentTempVbOffset, vb.Stride);
currentTempVbOffset += requiredSize;
_vertexBuffersLimited |= 1u << vbIndex;
@@ -234,7 +234,7 @@ namespace Ryujinx.Graphics.OpenGL
ref VertexBufferDescriptor vb = ref _vertexBuffers[vbIndex];
- GL.BindVertexBuffer(vbIndex, vb.Buffer.Handle.ToInt32(), (nint)vb.Buffer.Offset, vb.Stride);
+ GL.BindVertexBuffer(vbIndex, vb.Buffer.Handle, (nint)vb.Buffer.Offset, vb.Stride);
buffersLimited &= ~(1u << vbIndex);
}
diff --git a/src/Ryujinx.Graphics.OpenGL/Window.cs b/src/Ryujinx.Graphics.OpenGL/Window.cs
index bb4df0c06..fb3208f00 100644
--- a/src/Ryujinx.Graphics.OpenGL/Window.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Window.cs
@@ -70,7 +70,7 @@ namespace Ryujinx.Graphics.OpenGL
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);
- TextureView viewConverted = view.Format.IsBgr() ? _renderer.TextureCopy.BgraSwap(view) : view;
+ TextureView viewConverted = view.Format.IsBgr ? _renderer.TextureCopy.BgraSwap(view) : view;
UpdateEffect();
@@ -80,7 +80,7 @@ namespace Ryujinx.Graphics.OpenGL
viewConverted = _antiAliasing.Run(viewConverted, _width, _height);
- if (viewConverted.Format.IsBgr())
+ if (viewConverted.Format.IsBgr)
{
TextureView swappedView = _renderer.TextureCopy.BgraSwap(viewConverted);
@@ -152,14 +152,14 @@ namespace Ryujinx.Graphics.OpenGL
if (ScreenCaptureRequested)
{
- CaptureFrame(srcX0, srcY0, srcX1, srcY1, view.Format.IsBgr(), crop.FlipX, crop.FlipY);
+ CaptureFrame(srcX0, srcY0, srcX1, srcY1, view.Format.IsBgr, crop.FlipX, crop.FlipY);
ScreenCaptureRequested = false;
}
if (_scalingFilter != null)
{
- if (viewConverted.Format.IsBgr() && !_isBgra)
+ if (viewConverted.Format.IsBgr && !_isBgra)
{
RecreateUpscalingTexture(true);
}
diff --git a/src/Ryujinx.Graphics.Shader/AttributeType.cs b/src/Ryujinx.Graphics.Shader/AttributeType.cs
index 4c2913416..524453287 100644
--- a/src/Ryujinx.Graphics.Shader/AttributeType.cs
+++ b/src/Ryujinx.Graphics.Shader/AttributeType.cs
@@ -20,20 +20,18 @@ namespace Ryujinx.Graphics.Shader
static class AttributeTypeExtensions
{
- public static AggregateType ToAggregateType(this AttributeType type)
+ extension(AttributeType type)
{
- return (type & ~AttributeType.AnyPacked) switch
+ public AggregateType Aggregate =>
+ (type & ~AttributeType.AnyPacked) switch
{
AttributeType.Float => AggregateType.FP32,
AttributeType.Sint => AggregateType.S32,
AttributeType.Uint => AggregateType.U32,
_ => throw new ArgumentException($"Invalid attribute type \"{type}\"."),
};
- }
-
- public static AggregateType ToAggregateType(this AttributeType type, bool supportsScaledFormats)
- {
- return (type & ~AttributeType.AnyPacked) switch
+
+ public AggregateType AsAggregate(bool supportsScaledFormats) => (type & ~AttributeType.AnyPacked) switch
{
AttributeType.Float => AggregateType.FP32,
AttributeType.Sint => AggregateType.S32,
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index e0d7cdc4b..a7b82e742 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -83,7 +83,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
if (context.Definitions.Stage == ShaderStage.Geometry)
{
- string inPrimitive = context.Definitions.InputTopology.ToGlslString();
+ string inPrimitive = context.Definitions.InputTopology.GlslString;
context.AppendLine($"layout (invocations = {context.Definitions.ThreadsPerInputPrimitive}, {inPrimitive}) in;");
@@ -98,7 +98,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
else
{
- string outPrimitive = context.Definitions.OutputTopology.ToGlslString();
+ string outPrimitive = context.Definitions.OutputTopology.GlslString;
int maxOutputVertices = context.Definitions.MaxOutputVertices;
context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;");
@@ -123,8 +123,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
tessCw = !tessCw;
}
- string patchType = context.Definitions.TessPatchType.ToGlsl();
- string spacing = context.Definitions.TessSpacing.ToGlsl();
+ string patchType = context.Definitions.TessPatchType.Glsl;
+ string spacing = context.Definitions.TessSpacing.Glsl;
string windingOrder = tessCw ? "cw" : "ccw";
context.AppendLine($"layout ({patchType}, {spacing}, {windingOrder}) in;");
@@ -351,7 +351,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
arrayDecl = "[]";
}
- string samplerTypeName = definition.Separate ? definition.Type.ToGlslTextureType() : definition.Type.ToGlslSamplerType();
+ string samplerTypeName = definition.Separate ? definition.Type.GlslTextureTypeName : definition.Type.GlslSamplerTypeName;
string layout = string.Empty;
@@ -379,7 +379,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
arrayDecl = "[]";
}
- string imageTypeName = definition.Type.ToGlslImageType(definition.Format.GetComponentType());
+ string imageTypeName = definition.Type.GetGlslImageTypeName(definition.Format.GetComponentType());
if (definition.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
{
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index 32c930557..881ca0d47 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -54,7 +54,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
texCallBuilder.Append('(');
texCallBuilder.Append(imageName);
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount + (isArray ? 1 : 0);
@@ -162,7 +162,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
AstTextureOperation texOp = (AstTextureOperation)operation;
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int coordsIndex = 0;
string samplerName = GetSamplerName(context, texOp, ref coordsIndex);
@@ -264,7 +264,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
texCall += "(" + samplerName;
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount;
@@ -658,7 +658,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
samplerName = $"{samplerName}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]";
}
- name = $"{texOp.Type.ToGlslSamplerType()}({name}, {samplerName})";
+ name = $"{texOp.Type.GlslSamplerTypeName}({name}, {samplerName})";
}
return name;
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
index c0a597a10..e1571fc78 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Declarations.cs
@@ -385,12 +385,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
private static void DeclarePerVertexBlock(CodeGenContext context)
{
- if (context.Definitions.Stage.IsVtg())
+ if (context.Definitions.Stage.IsVtg)
{
if (context.Definitions.Stage != ShaderStage.Vertex)
{
SpvInstruction perVertexInputStructType = CreatePerVertexStructType(context);
- int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.ToInputVertices() : 32;
+ int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.InputVertexCount : 32;
SpvInstruction perVertexInputArrayType = context.TypeArray(perVertexInputStructType, context.Constant(context.TypeU32(), arraySize));
SpvInstruction perVertexInputPointerType = context.TypePointer(StorageClass.Input, perVertexInputArrayType);
SpvInstruction perVertexInputVariable = context.Variable(perVertexInputPointerType, StorageClass.Input);
@@ -537,7 +537,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
if (!isPerPatch && IoMap.IsPerVertex(ioVariable, context.Definitions.Stage, isOutput))
{
- int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.ToInputVertices() : 32;
+ int arraySize = context.Definitions.Stage == ShaderStage.Geometry ? context.Definitions.InputTopology.InputVertexCount : 32;
spvType = context.TypeArray(spvType, context.Constant(context.TypeU32(), arraySize));
if (context.Definitions.GpPassthrough && context.HostCapabilities.SupportsGeometryShaderPassthrough)
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
index 27b5c21c0..83b037c1c 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
@@ -615,7 +615,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
image = context.AccessChain(imagePointerType, image, textureIndex);
}
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount + (isArray ? 1 : 0);
@@ -693,7 +693,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
image = context.Load(declaration.ImageType, image);
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount + (isArray ? 1 : 0);
@@ -750,7 +750,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
image = context.Load(declaration.ImageType, image);
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount + (isArray ? 1 : 0);
@@ -840,7 +840,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
- int pCount = texOp.Type.GetDimensions();
+ int pCount = texOp.Type.Dimensions;
SpvInstruction pCoords;
@@ -1164,7 +1164,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int pCount = coordsCount;
@@ -1463,7 +1463,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
SamplerType type = context.SamplersTypes[texOp.GetTextureSetAndBinding()];
bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer;
- int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions();
+ int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.Dimensions;
if (type.HasFlag(SamplerType.Array))
{
@@ -1486,7 +1486,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
if (dimensions != 1)
{
- result = context.CompositeExtract(context.TypeS32(), result, (SpvLiteralInteger)texOp.Index);
+ result = context.CompositeExtract(context.TypeS32(), result, texOp.Index);
}
return new OperationResult(AggregateType.S32, result);
diff --git a/src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs b/src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
index ac1f24218..45250a463 100644
--- a/src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
+++ b/src/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
@@ -457,7 +457,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
case AttributeConsts.ClipDistance5:
case AttributeConsts.ClipDistance6:
case AttributeConsts.ClipDistance7:
- if (definitions.Stage.IsVtg())
+ if (definitions.Stage.IsVtg)
{
context.SetClipDistanceWritten((attr - AttributeConsts.ClipDistance0) / 4);
}
diff --git a/src/Ryujinx.Graphics.Shader/InputTopology.cs b/src/Ryujinx.Graphics.Shader/InputTopology.cs
index 9438263de..074386b5d 100644
--- a/src/Ryujinx.Graphics.Shader/InputTopology.cs
+++ b/src/Ryujinx.Graphics.Shader/InputTopology.cs
@@ -11,9 +11,9 @@ namespace Ryujinx.Graphics.Shader
static class InputTopologyExtensions
{
- public static string ToGlslString(this InputTopology topology)
+ extension(InputTopology topology)
{
- return topology switch
+ public string GlslString => topology switch
{
InputTopology.Points => "points",
InputTopology.Lines => "lines",
@@ -22,11 +22,8 @@ namespace Ryujinx.Graphics.Shader
InputTopology.TrianglesAdjacency => "triangles_adjacency",
_ => "points",
};
- }
-
- public static int ToInputVertices(this InputTopology topology)
- {
- return topology switch
+
+ public int InputVertexCount => topology switch
{
InputTopology.Points => 1,
InputTopology.Lines => 2,
@@ -35,17 +32,14 @@ namespace Ryujinx.Graphics.Shader
InputTopology.TrianglesAdjacency => 6,
_ => 1,
};
- }
-
- public static int ToInputVerticesNoAdjacency(this InputTopology topology)
- {
- return topology switch
+
+ public int InputVertexCountNoAdjacency => topology switch
{
InputTopology.Points => 1,
InputTopology.Lines or
- InputTopology.LinesAdjacency => 2,
+ InputTopology.LinesAdjacency => 2,
InputTopology.Triangles or
- InputTopology.TrianglesAdjacency => 3,
+ InputTopology.TrianglesAdjacency => 3,
_ => 1,
};
}
diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
index df84c38f1..4c7127274 100644
--- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
+++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
@@ -105,7 +105,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- src = Const(context.TranslatorContext.Definitions.InputTopology.ToInputVertices() << 16);
+ src = Const(context.TranslatorContext.Definitions.InputTopology.InputVertexCount << 16);
}
}
else
diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs
index e9f930179..2f86f044d 100644
--- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs
+++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs
@@ -228,7 +228,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
sourcesList.Add(context.Copy(GetSrcReg(context, srcC)));
}
- int coordsCount = type.GetDimensions();
+ int coordsCount = type.Dimensions;
for (int index = 0; index < coordsCount; index++)
{
@@ -335,7 +335,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
sourcesList.Add(context.Copy(Register(srcC, RegisterType.Gpr)));
}
- int coordsCount = type.GetDimensions();
+ int coordsCount = type.Dimensions;
for (int index = 0; index < coordsCount; index++)
{
@@ -507,7 +507,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
sourcesList.Add(context.Copy(GetSrcReg(context, srcC)));
}
- int coordsCount = type.GetDimensions();
+ int coordsCount = type.Dimensions;
for (int index = 0; index < coordsCount; index++)
{
@@ -612,7 +612,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
sourcesList.Add(context.Copy(Register(srcC, RegisterType.Gpr)));
}
- int coordsCount = type.GetDimensions();
+ int coordsCount = type.Dimensions;
for (int index = 0; index < coordsCount; index++)
{
diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
index 19b22e03b..fa0b87317 100644
--- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
+++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs
@@ -227,7 +227,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
}
- int coordsCount = type.GetDimensions();
+ int coordsCount = type.Dimensions;
for (int index = 0; index < coordsCount; index++)
{
@@ -558,7 +558,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if ((flags & TextureFlags.Offset) != 0)
{
- AddTextureOffset(type.GetDimensions(), 4, 4);
+ AddTextureOffset(type.Dimensions, 4, 4);
}
}
else if (texsType == TexsType.Tld4s)
@@ -583,7 +583,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (tld4sOp.Aoffi)
{
- AddTextureOffset(type.GetDimensions(), 8, 6);
+ AddTextureOffset(type.Dimensions, 8, 6);
flags |= TextureFlags.Offset;
}
@@ -714,7 +714,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
flags |= TextureFlags.Bindless;
}
- int coordsCount = type.GetDimensions();
+ int coordsCount = type.Dimensions;
for (int index = 0; index < coordsCount; index++)
{
@@ -847,7 +847,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
SamplerType type = ConvertSamplerType(dimensions);
- int coordsCount = type.GetDimensions();
+ int coordsCount = type.Dimensions;
bool isArray =
dimensions is TexDim.Array1d or
@@ -942,26 +942,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
return;
}
- Operand Ra()
- {
- if (srcA > RegisterConsts.RegisterZeroIndex)
- {
- return Const(0);
- }
-
- return context.Copy(Register(srcA++, RegisterType.Gpr));
- }
-
- Operand Rb()
- {
- if (srcB > RegisterConsts.RegisterZeroIndex)
- {
- return Const(0);
- }
-
- return context.Copy(Register(srcB++, RegisterType.Gpr));
- }
-
TextureFlags flags = TextureFlags.Derivatives;
List sourcesList = [];
@@ -975,7 +955,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
SamplerType type = ConvertSamplerType(dimensions);
- int coordsCount = type.GetDimensions();
+ int coordsCount = type.Dimensions;
for (int index = 0; index < coordsCount; index++)
{
@@ -1051,6 +1031,28 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
EmitTextureSample(context, type, flags, imm, componentMask, dests, sources);
+
+ return;
+
+ Operand Ra()
+ {
+ if (srcA > RegisterConsts.RegisterZeroIndex)
+ {
+ return Const(0);
+ }
+
+ return context.Copy(Register(srcA++, RegisterType.Gpr));
+ }
+
+ Operand Rb()
+ {
+ if (srcB > RegisterConsts.RegisterZeroIndex)
+ {
+ return Const(0);
+ }
+
+ return context.Copy(Register(srcB++, RegisterType.Gpr));
+ }
}
private static void EmitTxq(
diff --git a/src/Ryujinx.Graphics.Shader/OutputTopology.cs b/src/Ryujinx.Graphics.Shader/OutputTopology.cs
index dc4b304ad..a517fe861 100644
--- a/src/Ryujinx.Graphics.Shader/OutputTopology.cs
+++ b/src/Ryujinx.Graphics.Shader/OutputTopology.cs
@@ -9,9 +9,10 @@ namespace Ryujinx.Graphics.Shader
static class OutputTopologyExtensions
{
- public static string ToGlslString(this OutputTopology topology)
+
+ extension(OutputTopology topology)
{
- return topology switch
+ public string GlslString => topology switch
{
OutputTopology.LineStrip => "line_strip",
OutputTopology.PointList => "points",
diff --git a/src/Ryujinx.Graphics.Shader/SamplerType.cs b/src/Ryujinx.Graphics.Shader/SamplerType.cs
index a693495fa..88449ef66 100644
--- a/src/Ryujinx.Graphics.Shader/SamplerType.cs
+++ b/src/Ryujinx.Graphics.Shader/SamplerType.cs
@@ -22,9 +22,9 @@ namespace Ryujinx.Graphics.Shader
static class SamplerTypeExtensions
{
- public static int GetDimensions(this SamplerType type)
+ extension(SamplerType type)
{
- return (type & SamplerType.Mask) switch
+ public int Dimensions => (type & SamplerType.Mask) switch
{
SamplerType.Texture1D => 1,
SamplerType.TextureBuffer => 1,
@@ -33,127 +33,136 @@ namespace Ryujinx.Graphics.Shader
SamplerType.TextureCube => 3,
_ => throw new ArgumentException($"Invalid sampler type \"{type}\"."),
};
- }
- public static string ToShortSamplerType(this SamplerType type)
- {
- string typeName = (type & SamplerType.Mask) switch
+ public string ShortTypeName
{
- SamplerType.Texture1D => "1d",
- SamplerType.TextureBuffer => "b",
- SamplerType.Texture2D => "2d",
- SamplerType.Texture3D => "3d",
- SamplerType.TextureCube => "cube",
- _ => throw new ArgumentException($"Invalid sampler type \"{type}\"."),
- };
+ get
+ {
+ string typeName = (type & SamplerType.Mask) switch
+ {
+ SamplerType.Texture1D => "1d",
+ SamplerType.TextureBuffer => "b",
+ SamplerType.Texture2D => "2d",
+ SamplerType.Texture3D => "3d",
+ SamplerType.TextureCube => "cube",
+ _ => throw new ArgumentException($"Invalid sampler type \"{type}\"."),
+ };
- if ((type & SamplerType.Multisample) != 0)
- {
- typeName += "ms";
+ if ((type & SamplerType.Multisample) != 0)
+ {
+ typeName += "ms";
+ }
+
+ if ((type & SamplerType.Array) != 0)
+ {
+ typeName += "a";
+ }
+
+ if ((type & SamplerType.Shadow) != 0)
+ {
+ typeName += "s";
+ }
+
+ return typeName;
+ }
}
- if ((type & SamplerType.Array) != 0)
+ public string GlslSamplerTypeName
{
- typeName += "a";
+ get
+ {
+ string typeName = (type & SamplerType.Mask) switch
+ {
+ SamplerType.None => "sampler",
+ SamplerType.Texture1D => "sampler1D",
+ SamplerType.TextureBuffer => "samplerBuffer",
+ SamplerType.Texture2D => "sampler2D",
+ SamplerType.Texture3D => "sampler3D",
+ SamplerType.TextureCube => "samplerCube",
+ _ => throw new ArgumentException($"Invalid sampler type \"{type}\"."),
+ };
+
+ if ((type & SamplerType.Multisample) != 0)
+ {
+ typeName += "MS";
+ }
+
+ if ((type & SamplerType.Array) != 0)
+ {
+ typeName += "Array";
+ }
+
+ if ((type & SamplerType.Shadow) != 0)
+ {
+ typeName += "Shadow";
+ }
+
+ return typeName;
+ }
}
- if ((type & SamplerType.Shadow) != 0)
+ public string GlslTextureTypeName
{
- typeName += "s";
+ get
+ {
+ string typeName = (type & SamplerType.Mask) switch
+ {
+ SamplerType.Texture1D => "texture1D",
+ SamplerType.TextureBuffer => "textureBuffer",
+ SamplerType.Texture2D => "texture2D",
+ SamplerType.Texture3D => "texture3D",
+ SamplerType.TextureCube => "textureCube",
+ _ => throw new ArgumentException($"Invalid texture type \"{type}\"."),
+ };
+
+ if ((type & SamplerType.Multisample) != 0)
+ {
+ typeName += "MS";
+ }
+
+ if ((type & SamplerType.Array) != 0)
+ {
+ typeName += "Array";
+ }
+
+ return typeName;
+ }
}
- return typeName;
- }
-
- public static string ToGlslSamplerType(this SamplerType type)
- {
- string typeName = (type & SamplerType.Mask) switch
+ public string GetGlslImageTypeName(AggregateType componentType)
{
- SamplerType.None => "sampler",
- SamplerType.Texture1D => "sampler1D",
- SamplerType.TextureBuffer => "samplerBuffer",
- SamplerType.Texture2D => "sampler2D",
- SamplerType.Texture3D => "sampler3D",
- SamplerType.TextureCube => "samplerCube",
- _ => throw new ArgumentException($"Invalid sampler type \"{type}\"."),
- };
+ string typeName = (type & SamplerType.Mask) switch
+ {
+ SamplerType.Texture1D => "image1D",
+ SamplerType.TextureBuffer => "imageBuffer",
+ SamplerType.Texture2D => "image2D",
+ SamplerType.Texture3D => "image3D",
+ SamplerType.TextureCube => "imageCube",
+ _ => throw new ArgumentException($"Invalid sampler type \"{type}\"."),
+ };
- if ((type & SamplerType.Multisample) != 0)
- {
- typeName += "MS";
+ if ((type & SamplerType.Multisample) != 0)
+ {
+ typeName += "MS";
+ }
+
+ if ((type & SamplerType.Array) != 0)
+ {
+ typeName += "Array";
+ }
+
+ switch (componentType)
+ {
+ case AggregateType.U32:
+ typeName = 'u' + typeName;
+ break;
+ case AggregateType.S32:
+ typeName = 'i' + typeName;
+ break;
+ }
+
+ return typeName;
}
-
- if ((type & SamplerType.Array) != 0)
- {
- typeName += "Array";
- }
-
- if ((type & SamplerType.Shadow) != 0)
- {
- typeName += "Shadow";
- }
-
- return typeName;
- }
-
- public static string ToGlslTextureType(this SamplerType type)
- {
- string typeName = (type & SamplerType.Mask) switch
- {
- SamplerType.Texture1D => "texture1D",
- SamplerType.TextureBuffer => "textureBuffer",
- SamplerType.Texture2D => "texture2D",
- SamplerType.Texture3D => "texture3D",
- SamplerType.TextureCube => "textureCube",
- _ => throw new ArgumentException($"Invalid texture type \"{type}\"."),
- };
-
- if ((type & SamplerType.Multisample) != 0)
- {
- typeName += "MS";
- }
-
- if ((type & SamplerType.Array) != 0)
- {
- typeName += "Array";
- }
-
- return typeName;
- }
-
- public static string ToGlslImageType(this SamplerType type, AggregateType componentType)
- {
- string typeName = (type & SamplerType.Mask) switch
- {
- SamplerType.Texture1D => "image1D",
- SamplerType.TextureBuffer => "imageBuffer",
- SamplerType.Texture2D => "image2D",
- SamplerType.Texture3D => "image3D",
- SamplerType.TextureCube => "imageCube",
- _ => throw new ArgumentException($"Invalid sampler type \"{type}\"."),
- };
-
- if ((type & SamplerType.Multisample) != 0)
- {
- typeName += "MS";
- }
-
- if ((type & SamplerType.Array) != 0)
- {
- typeName += "Array";
- }
-
- switch (componentType)
- {
- case AggregateType.U32:
- typeName = 'u' + typeName;
- break;
- case AggregateType.S32:
- typeName = 'i' + typeName;
- break;
- }
-
- return typeName;
}
}
}
diff --git a/src/Ryujinx.Graphics.Shader/ShaderStage.cs b/src/Ryujinx.Graphics.Shader/ShaderStage.cs
index faea5c357..cbfd1aa0c 100644
--- a/src/Ryujinx.Graphics.Shader/ShaderStage.cs
+++ b/src/Ryujinx.Graphics.Shader/ShaderStage.cs
@@ -14,27 +14,23 @@ namespace Ryujinx.Graphics.Shader
public static class ShaderStageExtensions
{
- ///
- /// Checks if the shader stage supports render scale.
- ///
- /// Shader stage
- /// True if the shader stage supports render scale, false otherwise
- public static bool SupportsRenderScale(this ShaderStage stage)
+ extension(ShaderStage shaderStage)
{
- return stage is ShaderStage.Vertex or ShaderStage.Fragment or ShaderStage.Compute;
- }
-
- ///
- /// Checks if the shader stage is vertex, tessellation or geometry.
- ///
- /// Shader stage
- /// True if the shader stage is vertex, tessellation or geometry, false otherwise
- public static bool IsVtg(this ShaderStage stage)
- {
- return stage is ShaderStage.Vertex or
- ShaderStage.TessellationControl or
- ShaderStage.TessellationEvaluation or
- ShaderStage.Geometry;
+ ///
+ /// Checks if the shader stage supports render scale.
+ ///
+ public bool SupportsRenderScale =>
+ shaderStage is ShaderStage.Vertex or ShaderStage.Fragment or ShaderStage.Compute;
+
+ ///
+ /// Checks if the shader stage is vertex, tessellation or geometry.
+ ///
+ public bool IsVtg =>
+ shaderStage is ShaderStage.Vertex or
+ ShaderStage.TessellationControl or
+ ShaderStage.TessellationEvaluation or
+ ShaderStage.Geometry;
}
+
}
}
diff --git a/src/Ryujinx.Graphics.Shader/TessPatchType.cs b/src/Ryujinx.Graphics.Shader/TessPatchType.cs
index 76be22fd4..6c4fc1a30 100644
--- a/src/Ryujinx.Graphics.Shader/TessPatchType.cs
+++ b/src/Ryujinx.Graphics.Shader/TessPatchType.cs
@@ -9,9 +9,9 @@ namespace Ryujinx.Graphics.Shader
static class TessPatchTypeExtensions
{
- public static string ToGlsl(this TessPatchType type)
+ extension(TessPatchType patchType)
{
- return type switch
+ public string Glsl => patchType switch
{
TessPatchType.Isolines => "isolines",
TessPatchType.Quads => "quads",
diff --git a/src/Ryujinx.Graphics.Shader/TessSpacing.cs b/src/Ryujinx.Graphics.Shader/TessSpacing.cs
index 6035366c1..8d42ccbf1 100644
--- a/src/Ryujinx.Graphics.Shader/TessSpacing.cs
+++ b/src/Ryujinx.Graphics.Shader/TessSpacing.cs
@@ -9,9 +9,9 @@ namespace Ryujinx.Graphics.Shader
static class TessSpacingExtensions
{
- public static string ToGlsl(this TessSpacing spacing)
+ extension(TessSpacing spacing)
{
- return spacing switch
+ public string Glsl => spacing switch
{
TessSpacing.FractionalEventSpacing => "fractional_even_spacing",
TessSpacing.FractionalOddSpacing => "fractional_odd_spacing",
diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 94448626f..62dd9e2e7 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -135,7 +135,7 @@ namespace Ryujinx.Graphics.Shader.Translation
}
else if (TranslatorContext.Stage == ShaderStage.Geometry)
{
- int inputVertices = TranslatorContext.Definitions.InputTopology.ToInputVertices();
+ int inputVertices = TranslatorContext.Definitions.InputTopology.InputVertexCount;
Operand baseVertex = this.IMultiply(outputVertexOffset, Const(inputVertices));
@@ -404,7 +404,7 @@ namespace Ryujinx.Graphics.Shader.Translation
else
{
inputStart = 0;
- inputEnd = topology.ToInputVerticesNoAdjacency();
+ inputEnd = topology.InputVertexCountNoAdjacency;
inputStep = 1;
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
index 1f2f79a2d..c40568a61 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs
@@ -39,8 +39,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
// Set any destination variables to zero.
string typeName = texOp.Inst.IsImage()
- ? texOp.Type.ToGlslImageType(texOp.Format.GetComponentType())
- : texOp.Type.ToGlslTextureType();
+ ? texOp.Type.GetGlslImageTypeName(texOp.Format.GetComponentType())
+ : texOp.Type.GlslTextureTypeName;
gpuAccessor.Log($"Failed to find handle source for bindless access of type \"{typeName}\".");
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
index 2d366be71..2fc15344e 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ResourceManager.cs
@@ -133,7 +133,7 @@ namespace Ryujinx.Graphics.Shader.Translation
}
else if (stage == ShaderStage.Geometry)
{
- LocalTopologyRemapMemoryId = AddMemoryDefinition("local_topology_remap", AggregateType.Array | AggregateType.U32, inputTopology.ToInputVertices());
+ LocalTopologyRemapMemoryId = AddMemoryDefinition("local_topology_remap", AggregateType.Array | AggregateType.U32, inputTopology.InputVertexCount);
LocalGeometryOutputVertexCountMemoryId = AddMemoryDefinition("local_geometry_output_vertex", AggregateType.U32);
LocalGeometryOutputIndexCountMemoryId = AddMemoryDefinition("local_geometry_output_index", AggregateType.U32);
@@ -273,7 +273,7 @@ namespace Ryujinx.Graphics.Shader.Translation
bool coherent,
bool separate)
{
- int dimensions = type == SamplerType.None ? 0 : type.GetDimensions();
+ int dimensions = type == SamplerType.None ? 0 : type.Dimensions;
Dictionary dict = isImage ? _usedImages : _usedTextures;
TextureUsageFlags usageFlags = TextureUsageFlags.None;
@@ -282,7 +282,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
usageFlags |= TextureUsageFlags.NeedsScaleValue;
- bool canScale = _stage.SupportsRenderScale() && arrayLength == 1 && !write && dimensions == 2;
+ bool canScale = _stage.SupportsRenderScale && arrayLength == 1 && !write && dimensions == 2;
if (!canScale)
{
@@ -355,7 +355,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (arrayLength != 1 && type != SamplerType.None)
{
- prefix += type.ToShortSamplerType();
+ prefix += type.ShortTypeName;
}
if (isImage)
@@ -432,9 +432,9 @@ namespace Ryujinx.Graphics.Shader.Translation
if (found)
{
selectedMeta.UsageFlags |= TextureUsageFlags.NeedsScaleValue;
-
- int dimensions = type.GetDimensions();
- bool canScale = _stage.SupportsRenderScale() && selectedInfo.ArrayLength == 1 && dimensions == 2;
+
+ int dimensions = type.Dimensions;
+ bool canScale = _stage.SupportsRenderScale && selectedInfo.ArrayLength == 1 && dimensions == 2;
if (!canScale)
{
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs b/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs
index 656ad6c5e..c11e65812 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs
@@ -157,7 +157,7 @@ namespace Ryujinx.Graphics.Shader.Translation
GpPassthrough = gpPassthrough;
ThreadsPerInputPrimitive = threadsPerInputPrimitive;
OutputTopology = outputTopology;
- MaxOutputVertices = gpPassthrough ? graphicsState.Topology.ToInputVerticesNoAdjacency() : maxOutputVertices;
+ MaxOutputVertices = gpPassthrough ? graphicsState.Topology.InputVertexCountNoAdjacency : maxOutputVertices;
ImapTypes = imapTypes;
OmapTargets = omapTargets;
OmapSampleMask = omapSampleMask;
@@ -293,7 +293,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public AggregateType GetFragmentOutputColorType(int location)
{
- return AggregateType.Vector4 | _graphicsState.FragmentOutputTypes[location].ToAggregateType();
+ return AggregateType.Vector4 | _graphicsState.FragmentOutputTypes[location].Aggregate;
}
public AggregateType GetUserDefinedType(int location, bool isOutput)
@@ -307,7 +307,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (Stage == ShaderStage.Vertex && !isOutput)
{
- type |= _graphicsState.AttributeTypes[location].ToAggregateType(SupportsScaledVertexFormats);
+ type |= _graphicsState.AttributeTypes[location].AsAggregate(SupportsScaledVertexFormats);
}
else
{
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Transforms/TexturePass.cs b/src/Ryujinx.Graphics.Shader/Translation/Transforms/TexturePass.cs
index 808692559..2ec00ce2d 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Transforms/TexturePass.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Transforms/TexturePass.cs
@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
(intCoords || isImage) &&
!isBindless &&
!isIndexed &&
- stage.SupportsRenderScale() &&
+ stage.SupportsRenderScale &&
TypeSupportsScale(texOp.Type))
{
int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.TexelFetchScale);
@@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
? resourceManager.GetTextureDescriptors(includeArrays: false).Length + resourceManager.FindImageDescriptorIndex(texOp.Binding)
: resourceManager.FindTextureDescriptorIndex(texOp.Binding);
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int coordsIndex = isBindless ? 1 : 0;
for (int index = 0; index < coordsCount; index++)
@@ -103,7 +103,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
texOp.Index < 2 &&
!isBindless &&
!isIndexed &&
- stage.SupportsRenderScale() &&
+ stage.SupportsRenderScale &&
TypeSupportsScale(texOp.Type))
{
int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.TextureSizeUnscale);
@@ -168,7 +168,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
return node;
}
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int normCoordsCount = (texOp.Type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : coordsCount;
@@ -226,7 +226,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
bool isIndexed = resourceManager.IsArrayOfTexturesOrImages(texOp.Binding, isImage: false);
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int coordsIndex = isBindless || isIndexed ? 1 : 0;
int normCoordsCount = (texOp.Type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : coordsCount;
@@ -315,7 +315,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0;
bool isShadow = (texOp.Type & SamplerType.Shadow) != 0;
- int coordsCount = texOp.Type.GetDimensions();
+ int coordsCount = texOp.Type.Dimensions;
int offsetsCount;
diff --git a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs
index 38cd02449..ca0e79b8b 100644
--- a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs
+++ b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs
@@ -368,10 +368,13 @@ namespace Ryujinx.Graphics.Vulkan
}
}
- public BufferHandle GetHandle()
+ public BufferHandle Handle
{
- ulong handle = _bufferHandle;
- return Unsafe.As(ref handle);
+ get
+ {
+ ulong handle = _bufferHandle;
+ return Unsafe.As(ref handle);
+ }
}
public nint Map(int offset, int mappingSize)
diff --git a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
index aee55fef4..605105ea8 100644
--- a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
+++ b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
@@ -158,16 +158,16 @@ namespace Ryujinx.Graphics.Vulkan
FormatFeatureFlags.TransferSrcBit |
FormatFeatureFlags.TransferDstBit;
- if (srcFormat.IsDepthOrStencil())
+ if (srcFormat.IsDepthOrStencil)
{
requiredFeatures |= FormatFeatureFlags.DepthStencilAttachmentBit;
}
- else if (srcFormat.IsRtColorCompatible())
+ else if (srcFormat.IsRtColorCompatible)
{
requiredFeatures |= FormatFeatureFlags.ColorAttachmentBit;
}
- if (srcFormat.IsImageCompatible() && storageFeatureFlagRequired)
+ if (srcFormat.IsImageCompatible && storageFeatureFlagRequired)
{
requiredFeatures |= FormatFeatureFlags.StorageImageBit;
}
diff --git a/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs b/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs
index 46b9cacb9..919c45b9d 100644
--- a/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs
+++ b/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
{
Format format = view.Info.Format;
- bool isDepthStencil = format.IsDepthOrStencil();
+ bool isDepthStencil = format.IsDepthOrStencil;
_device = device;
_attachments = [view.GetImageViewForAttachment()];
@@ -62,8 +62,8 @@ namespace Ryujinx.Graphics.Vulkan
AttachmentSamples = [(uint)view.Info.Samples];
AttachmentFormats = [view.VkFormat];
AttachmentIndices = isDepthStencil ? [] : [0];
- AttachmentIntegerFormatMask = format.IsInteger() ? 1u : 0u;
- LogicOpsAllowed = !format.IsFloatOrSrgb();
+ AttachmentIntegerFormatMask = format.IsInt ? 1u : 0u;
+ LogicOpsAllowed = !format.IsFloatOrSrgb;
AttachmentsCount = 1;
_totalCount = 1;
@@ -113,12 +113,12 @@ namespace Ryujinx.Graphics.Vulkan
Format format = texture.Info.Format;
- if (format.IsInteger())
+ if (format.IsInt)
{
attachmentIntegerFormatMask |= 1u << bindIndex;
}
- allFormatsFloatOrSrgb &= format.IsFloatOrSrgb();
+ allFormatsFloatOrSrgb &= format.IsFloatOrSrgb;
width = Math.Min(width, (uint)texture.Width);
height = Math.Min(height, (uint)texture.Height);
@@ -250,12 +250,12 @@ namespace Ryujinx.Graphics.Vulkan
Format format = texture.Info.Format;
- if (format.IsInteger())
+ if (format.IsInt)
{
attachmentIntegerFormatMask |= 1u << bindIndex;
}
- allFormatsFloatOrSrgb &= format.IsFloatOrSrgb();
+ allFormatsFloatOrSrgb &= format.IsFloatOrSrgb;
width = Math.Min(width, (uint)texture.Width);
height = Math.Min(height, (uint)texture.Height);
@@ -330,12 +330,12 @@ namespace Ryujinx.Graphics.Vulkan
{
Format format = _colors[index].Info.Format;
- if (format.IsSint())
+ if (format.IsSignedInt)
{
return ComponentType.SignedInteger;
}
- if (format.IsUint())
+ if (format.IsUnsignedInt)
{
return ComponentType.UnsignedInteger;
}
diff --git a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs
index a60e060c0..dbb5ee224 100644
--- a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs
+++ b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs
@@ -402,14 +402,14 @@ namespace Ryujinx.Graphics.Vulkan
0f,
1f);
- bool dstIsDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
+ bool dstIsDepthOrStencil = dst.Info.Format.IsDepthOrStencil;
if (dstIsDepthOrStencil)
{
- _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
+ _pipeline.SetProgram(src.Info.Target.IsMultisample ? _programDepthBlitMs : _programDepthBlit);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
}
- else if (src.Info.Target.IsMultisample())
+ else if (src.Info.Target.IsMultisample)
{
_pipeline.SetProgram(_programColorBlitMs);
}
@@ -566,12 +566,12 @@ namespace Ryujinx.Graphics.Vulkan
if (isDepth)
{
- _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
+ _pipeline.SetProgram(src.Info.Target.IsMultisample ? _programDepthBlitMs : _programDepthBlit);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
}
else
{
- _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programStencilBlitMs : _programStencilBlit);
+ _pipeline.SetProgram(src.Info.Target.IsMultisample ? _programStencilBlitMs : _programStencilBlit);
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
}
@@ -1047,7 +1047,7 @@ namespace Ryujinx.Graphics.Vulkan
Span shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
int samples = src.Info.Samples;
- bool isDepthOrStencil = src.Info.Format.IsDepthOrStencil();
+ bool isDepthOrStencil = src.Info.Format.IsDepthOrStencil;
ImageAspectFlags aspectFlags = src.Info.Format.ConvertAspectFlags();
// X and Y are the expected texture samples.
@@ -1173,7 +1173,7 @@ namespace Ryujinx.Graphics.Vulkan
Span shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
int samples = dst.Info.Samples;
- bool isDepthOrStencil = src.Info.Format.IsDepthOrStencil();
+ bool isDepthOrStencil = src.Info.Format.IsDepthOrStencil;
ImageAspectFlags aspectFlags = src.Info.Format.ConvertAspectFlags();
// X and Y are the expected texture samples.
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
index 26682ad20..f2f68378f 100644
--- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
@@ -1181,7 +1181,7 @@ namespace Ryujinx.Graphics.Vulkan
if (!attribute.IsZero)
{
- newVbScalarSizes[rawIndex] = Math.Max(newVbScalarSizes[rawIndex], attribute.Format.GetScalarSize());
+ newVbScalarSizes[rawIndex] = Math.Max(newVbScalarSizes[rawIndex], attribute.Format.ScalarSize);
dirtyVbSizes |= 1u << rawIndex;
}
@@ -1575,7 +1575,7 @@ namespace Ryujinx.Graphics.Vulkan
// May need to enforce feedback loop layout here in the future.
// Though technically, it should always work with the general layout.
- if (view.Info.Format.IsDepthOrStencil())
+ if (view.Info.Format.IsDepthOrStencil)
{
if (_passWritesDepthStencil)
{
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs b/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs
index c259d91a9..e0bff2c15 100644
--- a/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs
@@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Vulkan
int maxColorAttachmentIndex = -1;
bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample ||
- !state.DepthStencilFormat.IsImageCompatible();
+ !state.DepthStencilFormat.IsImageCompatible;
Span attachmentEnableSpan = state.AttachmentEnable.AsSpan();
Span attachmentFormatsSpan = state.AttachmentFormats.AsSpan();
@@ -41,7 +41,7 @@ namespace Ryujinx.Graphics.Vulkan
if (attachmentEnableSpan[i])
{
bool isNotMsOrSupportsStorageAttachments = gd.Capabilities.SupportsShaderStorageImageMultisample ||
- !attachmentFormatsSpan[i].IsImageCompatible();
+ !attachmentFormatsSpan[i].IsImageCompatible;
attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(attachmentFormatsSpan[i], isNotMsOrSupportsStorageAttachments);
@@ -62,7 +62,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < attachmentCount; i++)
{
- int bindIndex = attachmentIndices[i];
+ //int bindIndex = attachmentIndices[i];
attachmentDescs[i] = new AttachmentDescription(
0,
@@ -242,7 +242,7 @@ namespace Ryujinx.Graphics.Vulkan
if (!attribute.IsZero && bufferIndex < vbCount)
{
- vbScalarSizes[bufferIndex - 1] = Math.Max(attribute.Format.GetScalarSize(), vbScalarSizes[bufferIndex - 1]);
+ vbScalarSizes[bufferIndex - 1] = Math.Max(attribute.Format.ScalarSize, vbScalarSizes[bufferIndex - 1]);
}
}
@@ -320,23 +320,23 @@ namespace Ryujinx.Graphics.Vulkan
if (attachmentEnableSpan[i])
{
bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample ||
- !attachmentFormatsSpan[i].IsImageCompatible();
+ !attachmentFormatsSpan[i].IsImageCompatible;
pAttachmentFormatsSpan[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(attachmentFormatsSpan[i], isNotMsOrSupportsStorage);
maxColorAttachmentIndex = i;
- if (attachmentFormatsSpan[i].IsInteger())
+ if (attachmentFormatsSpan[i].IsInt)
{
attachmentIntegerFormatMask |= 1u << i;
}
- allFormatsFloatOrSrgb &= attachmentFormatsSpan[i].IsFloatOrSrgb();
+ allFormatsFloatOrSrgb &= attachmentFormatsSpan[i].IsFloatOrSrgb;
}
}
if (state.DepthStencilEnable)
{
- bool isNotMsOrSupportsStorage = !state.DepthStencilFormat.IsImageCompatible() ||
+ bool isNotMsOrSupportsStorage = !state.DepthStencilFormat.IsImageCompatible ||
gd.Capabilities.SupportsShaderStorageImageMultisample;
pAttachmentFormatsSpan[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat, isNotMsOrSupportsStorage);
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs
index 36f5804bb..75fff2034 100644
--- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs
@@ -647,7 +647,7 @@ namespace Ryujinx.Graphics.Vulkan
{
result.ThrowOnError();
}
- else if (result.IsError())
+ else if (result.IsError)
{
program.AddGraphicsPipeline(ref Internal, null);
diff --git a/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs b/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs
index e0de5692c..aae3b0afb 100644
--- a/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs
+++ b/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs
@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Vulkan
ImageBlit.SrcOffsetsBuffer srcOffsets = new();
ImageBlit.DstOffsetsBuffer dstOffsets = new();
- Filter filter = linearFilter && !dstInfo.Format.IsDepthOrStencil() ? Filter.Linear : Filter.Nearest;
+ Filter filter = linearFilter && !dstInfo.Format.IsDepthOrStencil ? Filter.Linear : Filter.Nearest;
TextureView.InsertImageBarrier(
api,
diff --git a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs
index 3dc605891..46cd5b4be 100644
--- a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs
+++ b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs
@@ -77,7 +77,7 @@ namespace Ryujinx.Graphics.Vulkan
_device = device;
_info = info;
- bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample();
+ bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample;
VkFormat format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format, isMsImageStorageSupported);
uint levels = (uint)info.Levels;
@@ -311,16 +311,16 @@ namespace Ryujinx.Graphics.Vulkan
{
ImageUsageFlags usage = DefaultUsageFlags;
- if (format.IsDepthOrStencil())
+ if (format.IsDepthOrStencil)
{
usage |= ImageUsageFlags.DepthStencilAttachmentBit;
}
- else if (format.IsRtColorCompatible())
+ else if (format.IsRtColorCompatible)
{
usage |= ImageUsageFlags.ColorAttachmentBit;
}
- if ((format.IsImageCompatible() && isMsImageStorageSupported) || extendedUsage)
+ if ((format.IsImageCompatible && isMsImageStorageSupported) || extendedUsage)
{
usage |= ImageUsageFlags.StorageBit;
}
diff --git a/src/Ryujinx.Graphics.Vulkan/TextureView.cs b/src/Ryujinx.Graphics.Vulkan/TextureView.cs
index 1cbb7c6e1..4513c804f 100644
--- a/src/Ryujinx.Graphics.Vulkan/TextureView.cs
+++ b/src/Ryujinx.Graphics.Vulkan/TextureView.cs
@@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Vulkan
gd.Textures.Add(this);
- bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample();
+ bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample;
VkFormat format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format, isMsImageStorageSupported);
ImageUsageFlags usage = TextureStorage.GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported, false);
@@ -128,7 +128,7 @@ namespace Ryujinx.Graphics.Vulkan
ImageUsageFlags shaderUsage = ImageUsageFlags.SampledBit;
- if (info.Format.IsImageCompatible() && (_gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample()))
+ if (info.Format.IsImageCompatible && (_gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample))
{
shaderUsage |= ImageUsageFlags.StorageBit;
}
@@ -150,7 +150,7 @@ namespace Ryujinx.Graphics.Vulkan
{
if (gd.Capabilities.PortabilitySubset.HasFlag(PortabilitySubsetFlags.No3DImageView))
{
- if (levels == 1 && (info.Format.IsRtColorCompatible() || info.Format.IsDepthOrStencil()))
+ if (levels == 1 && (info.Format.IsRtColorCompatible || info.Format.IsDepthOrStencil))
{
subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, 1);
@@ -225,12 +225,12 @@ namespace Ryujinx.Graphics.Vulkan
Image srcImage = src.GetImage().Get(cbs).Value;
Image dstImage = dst.GetImage().Get(cbs).Value;
- if (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample())
+ if (!dst.Info.Target.IsMultisample && Info.Target.IsMultisample)
{
int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
_gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, 0, firstLayer, layers);
}
- else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample())
+ else if (dst.Info.Target.IsMultisample && !Info.Target.IsMultisample)
{
int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
_gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, 0, firstLayer, layers);
@@ -241,7 +241,7 @@ namespace Ryujinx.Graphics.Vulkan
int levels = Math.Min(Info.Levels, dst.Info.Levels - firstLevel);
_gd.HelperShader.CopyIncompatibleFormats(_gd, cbs, src, dst, 0, firstLayer, 0, firstLevel, layers, levels);
}
- else if (src.Info.Format.IsDepthOrStencil() != dst.Info.Format.IsDepthOrStencil())
+ else if (src.Info.Format.IsDepthOrStencil != dst.Info.Format.IsDepthOrStencil)
{
int layers = Math.Min(Info.GetLayers(), dst.Info.GetLayers() - firstLayer);
int levels = Math.Min(Info.Levels, dst.Info.Levels - firstLevel);
@@ -285,11 +285,11 @@ namespace Ryujinx.Graphics.Vulkan
Image srcImage = src.GetImage().Get(cbs).Value;
Image dstImage = dst.GetImage().Get(cbs).Value;
- if (!dst.Info.Target.IsMultisample() && Info.Target.IsMultisample())
+ if (!dst.Info.Target.IsMultisample && Info.Target.IsMultisample)
{
_gd.HelperShader.CopyMSToNonMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1);
}
- else if (dst.Info.Target.IsMultisample() && !Info.Target.IsMultisample())
+ else if (dst.Info.Target.IsMultisample && !Info.Target.IsMultisample)
{
_gd.HelperShader.CopyNonMSToMS(_gd, cbs, src, dst, srcLayer, dstLayer, 1);
}
@@ -297,7 +297,7 @@ namespace Ryujinx.Graphics.Vulkan
{
_gd.HelperShader.CopyIncompatibleFormats(_gd, cbs, src, dst, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
- else if (src.Info.Format.IsDepthOrStencil() != dst.Info.Format.IsDepthOrStencil())
+ else if (src.Info.Format.IsDepthOrStencil != dst.Info.Format.IsDepthOrStencil)
{
_gd.HelperShader.CopyColor(_gd, cbs, src, dst, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
@@ -370,7 +370,7 @@ namespace Ryujinx.Graphics.Vulkan
src.Height == dst.Height &&
src.VkFormat == dst.VkFormat)
{
- if (src.Info.Samples > 1 && src.Info.Samples != dst.Info.Samples && src.Info.Format.IsDepthOrStencil())
+ if (src.Info.Samples > 1 && src.Info.Samples != dst.Info.Samples && src.Info.Format.IsDepthOrStencil)
{
// CmdResolveImage does not support depth-stencil resolve, so we need to use an alternative path
// for those textures.
@@ -424,7 +424,7 @@ namespace Ryujinx.Graphics.Vulkan
}
}
- bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
+ bool isDepthOrStencil = dst.Info.Format.IsDepthOrStencil;
if (!VulkanConfiguration.UseUnsafeBlit || (_gd.Vendor != Vendor.Nvidia && _gd.Vendor != Vendor.Intel))
{
diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanException.cs b/src/Ryujinx.Graphics.Vulkan/VulkanException.cs
index 5d67ab838..1ccf0363a 100644
--- a/src/Ryujinx.Graphics.Vulkan/VulkanException.cs
+++ b/src/Ryujinx.Graphics.Vulkan/VulkanException.cs
@@ -5,18 +5,17 @@ namespace Ryujinx.Graphics.Vulkan
{
static class ResultExtensions
{
- public static bool IsError(this Result result)
+ extension(Result result)
{
- // Only negative result codes are errors.
- return result < Result.Success;
- }
+ public bool IsError => result < Result.Success;
- public static void ThrowOnError(this Result result)
- {
- // Only negative result codes are errors.
- if (result.IsError())
+ public void ThrowOnError()
{
- throw new VulkanException(result);
+ // Only negative result codes are errors.
+ if (result.IsError)
+ {
+ throw new VulkanException(result);
+ }
}
}
}
diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs
index b67b0dbfa..0a0d970c1 100644
--- a/src/Ryujinx.Graphics.Vulkan/Window.cs
+++ b/src/Ryujinx.Graphics.Vulkan/Window.cs
@@ -401,7 +401,7 @@ namespace Ryujinx.Graphics.Vulkan
cbs = _gd.CommandBufferPool.Rent();
}
- CaptureFrame(view, srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0, view.Info.Format.IsBgr(), crop.FlipX, crop.FlipY);
+ CaptureFrame(view, srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0, view.Info.Format.IsBgr, crop.FlipX, crop.FlipY);
ScreenCaptureRequested = false;
}
diff --git a/src/Ryujinx.HLE/HOS/Horizon.cs b/src/Ryujinx.HLE/HOS/Horizon.cs
index 517f8ef16..83aaa1f4d 100644
--- a/src/Ryujinx.HLE/HOS/Horizon.cs
+++ b/src/Ryujinx.HLE/HOS/Horizon.cs
@@ -122,8 +122,8 @@ namespace Ryujinx.HLE.HOS
TickSource,
device,
device.Memory,
- device.Configuration.MemoryConfiguration.ToKernelMemorySize(),
- device.Configuration.MemoryConfiguration.ToKernelMemoryArrange());
+ device.Configuration.MemoryConfiguration.KernelMemorySize,
+ device.Configuration.MemoryConfiguration.KernelMemoryArrange);
Device = device;
diff --git a/src/Ryujinx.HLE/HOS/HorizonFsClient.cs b/src/Ryujinx.HLE/HOS/HorizonFsClient.cs
index 56bc3bec3..cffd89413 100644
--- a/src/Ryujinx.HLE/HOS/HorizonFsClient.cs
+++ b/src/Ryujinx.HLE/HOS/HorizonFsClient.cs
@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS
public Result GetFileSize(out long size, FileHandle handle)
{
- return _fsClient.GetFileSize(out size, (LibHac.Fs.FileHandle)handle.Value).ToHorizonResult();
+ return _fsClient.GetFileSize(out size, (LibHac.Fs.FileHandle)handle.Value).Horizon;
}
public Result MountSystemData(string mountName, ulong dataId)
@@ -58,7 +58,7 @@ namespace Ryujinx.HLE.HOS
using IFileSystem ncaFileSystem = nca.OpenFileSystem(NcaSectionType.Data, _system.FsIntegrityCheckLevel);
using UniqueRef ncaFsRef = new(ncaFileSystem);
- Result result = _fsClient.Register(mountName.ToU8Span(), ref ncaFsRef.Ref).ToHorizonResult();
+ Result result = _fsClient.Register(mountName.ToU8Span(), ref ncaFsRef.Ref).Horizon;
if (result.IsFailure)
{
ncaStorage.Dispose();
@@ -74,14 +74,14 @@ namespace Ryujinx.HLE.HOS
{
ncaStorage?.Dispose();
- return ex.ResultValue.ToHorizonResult();
+ return ex.ResultValue.Horizon;
}
}
}
// TODO: Return correct result here, this is likely wrong.
- return LibHac.Fs.ResultFs.TargetNotFound.Handle().ToHorizonResult();
+ return LibHac.Fs.ResultFs.TargetNotFound.Handle().Horizon;
}
public Result OpenFile(out FileHandle handle, string path, OpenMode openMode)
@@ -89,7 +89,7 @@ namespace Ryujinx.HLE.HOS
LibHac.Result result = _fsClient.OpenFile(out LibHac.Fs.FileHandle libhacHandle, path.ToU8Span(), (LibHac.Fs.OpenMode)openMode);
handle = new(libhacHandle);
- return result.ToHorizonResult();
+ return result.Horizon;
}
public Result QueryMountSystemDataCacheSize(out long size, ulong dataId)
@@ -103,7 +103,7 @@ namespace Ryujinx.HLE.HOS
public Result ReadFile(FileHandle handle, long offset, Span destination)
{
- return _fsClient.ReadFile((LibHac.Fs.FileHandle)handle.Value, offset, destination).ToHorizonResult();
+ return _fsClient.ReadFile((LibHac.Fs.FileHandle)handle.Value, offset, destination).Horizon;
}
public void Unmount(string mountName)
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/CapabilityExtensions.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/CapabilityExtensions.cs
index dd133ee15..845ac850c 100644
--- a/src/Ryujinx.HLE/HOS/Kernel/Process/CapabilityExtensions.cs
+++ b/src/Ryujinx.HLE/HOS/Kernel/Process/CapabilityExtensions.cs
@@ -4,19 +4,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
static class CapabilityExtensions
{
+ extension(CapabilityType type)
+ {
+ public uint Flag => (uint)type + 1;
+
+ public uint Id => (uint)BitOperations.TrailingZeroCount(type.Flag);
+ }
+
public static CapabilityType GetCapabilityType(this uint cap)
{
return (CapabilityType)(((cap + 1) & ~cap) - 1);
}
-
- public static uint GetFlag(this CapabilityType type)
- {
- return (uint)type + 1;
- }
-
- public static uint GetId(this CapabilityType type)
- {
- return (uint)BitOperations.TrailingZeroCount(type.GetFlag());
- }
}
}
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
index 745d3edd8..2d9d0ef47 100644
--- a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
+++ b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
@@ -133,7 +133,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
return Result.Success;
}
- int codeMask = 1 << (32 - BitOperations.LeadingZeroCount(code.GetFlag() + 1));
+ int codeMask = 1 << (32 - BitOperations.LeadingZeroCount(code.Flag + 1));
// Check if the property was already set.
if (((mask0 & codeMask) & 0x1e008) != 0)
diff --git a/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
index 0d2fcaa2a..28db75663 100644
--- a/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
@@ -1316,8 +1316,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
context.Memory.Read(context.Request.PtrBuff[1].Position, vibrationValueBuffer);
- Span deviceHandles = MemoryMarshal.Cast(vibrationDeviceHandleBuffer);
- Span vibrationValues = MemoryMarshal.Cast(vibrationValueBuffer);
+ Span deviceHandles = MemoryMarshal.Cast(new Span(vibrationDeviceHandleBuffer));
+ Span vibrationValues = MemoryMarshal.Cast(new Span(vibrationValueBuffer));
if (!deviceHandles.IsEmpty && vibrationValues.Length == deviceHandles.Length)
{
diff --git a/src/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs b/src/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs
index 301d415a0..6a9b4d442 100644
--- a/src/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Spl/IGeneralInterface.cs
@@ -64,7 +64,7 @@ namespace Ryujinx.HLE.HOS.Services.Spl
#pragma warning disable IDE0059 // Remove unnecessary value assignment
SystemVersion version = context.Device.System.ContentManager.GetCurrentFirmwareVersion();
#pragma warning restore IDE0059
- MemorySize memorySize = context.Device.Configuration.MemoryConfiguration.ToKernelMemorySize();
+ MemorySize memorySize = context.Device.Configuration.MemoryConfiguration.KernelMemorySize;
switch (configItem)
{
diff --git a/src/Ryujinx.HLE/MemoryConfiguration.cs b/src/Ryujinx.HLE/MemoryConfiguration.cs
index 21ecd737f..9a397098a 100644
--- a/src/Ryujinx.HLE/MemoryConfiguration.cs
+++ b/src/Ryujinx.HLE/MemoryConfiguration.cs
@@ -18,11 +18,11 @@ namespace Ryujinx.HLE
{
private const ulong GiB = 1024 * 1024 * 1024;
-#pragma warning disable IDE0055 // Disable formatting
- public static MemoryArrange ToKernelMemoryArrange(this MemoryConfiguration configuration)
+ extension(MemoryConfiguration configuration)
{
- return configuration switch
+ public MemoryArrange KernelMemoryArrange => configuration switch
{
+#pragma warning disable IDE0055 // Disable formatting
MemoryConfiguration.MemoryConfiguration4GiB => MemoryArrange.MemoryArrange4GiB,
MemoryConfiguration.MemoryConfiguration4GiBAppletDev => MemoryArrange.MemoryArrange4GiBAppletDev,
MemoryConfiguration.MemoryConfiguration4GiBSystemDev => MemoryArrange.MemoryArrange4GiBSystemDev,
@@ -31,38 +31,36 @@ namespace Ryujinx.HLE
MemoryConfiguration.MemoryConfiguration8GiB => MemoryArrange.MemoryArrange8GiB,
MemoryConfiguration.MemoryConfiguration12GiB => MemoryArrange.MemoryArrange12GiB,
_ => throw new AggregateException($"Invalid memory configuration \"{configuration}\"."),
+#pragma warning restore IDE0055
};
- }
-
- public static MemorySize ToKernelMemorySize(this MemoryConfiguration configuration)
- {
- return configuration switch
+
+ public MemorySize KernelMemorySize => configuration switch
{
+#pragma warning disable IDE0055 // Disable formatting
MemoryConfiguration.MemoryConfiguration4GiB or
- MemoryConfiguration.MemoryConfiguration4GiBAppletDev or
- MemoryConfiguration.MemoryConfiguration4GiBSystemDev => MemorySize.MemorySize4GiB,
+ MemoryConfiguration.MemoryConfiguration4GiBAppletDev or
+ MemoryConfiguration.MemoryConfiguration4GiBSystemDev => MemorySize.MemorySize4GiB,
MemoryConfiguration.MemoryConfiguration6GiB or
- MemoryConfiguration.MemoryConfiguration6GiBAppletDev => MemorySize.MemorySize6GiB,
- MemoryConfiguration.MemoryConfiguration8GiB => MemorySize.MemorySize8GiB,
- MemoryConfiguration.MemoryConfiguration12GiB => MemorySize.MemorySize12GiB,
+ MemoryConfiguration.MemoryConfiguration6GiBAppletDev => MemorySize.MemorySize6GiB,
+ MemoryConfiguration.MemoryConfiguration8GiB => MemorySize.MemorySize8GiB,
+ MemoryConfiguration.MemoryConfiguration12GiB => MemorySize.MemorySize12GiB,
_ => throw new AggregateException($"Invalid memory configuration \"{configuration}\"."),
+#pragma warning restore IDE0055
};
- }
-
- public static ulong ToDramSize(this MemoryConfiguration configuration)
- {
- return configuration switch
+
+ public ulong DramSize => configuration switch
{
+#pragma warning disable IDE0055 // Disable formatting
MemoryConfiguration.MemoryConfiguration4GiB or
- MemoryConfiguration.MemoryConfiguration4GiBAppletDev or
- MemoryConfiguration.MemoryConfiguration4GiBSystemDev => 4 * GiB,
+ MemoryConfiguration.MemoryConfiguration4GiBAppletDev or
+ MemoryConfiguration.MemoryConfiguration4GiBSystemDev => 4 * GiB,
MemoryConfiguration.MemoryConfiguration6GiB or
- MemoryConfiguration.MemoryConfiguration6GiBAppletDev => 6 * GiB,
+ MemoryConfiguration.MemoryConfiguration6GiBAppletDev => 6 * GiB,
MemoryConfiguration.MemoryConfiguration8GiB => 8 * GiB,
MemoryConfiguration.MemoryConfiguration12GiB => 12 * GiB,
_ => throw new AggregateException($"Invalid memory configuration \"{configuration}\"."),
+#pragma warning restore IDE0055
};
}
-#pragma warning restore IDE0055
}
}
diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs
index 2ce9d9959..850c8b5fa 100644
--- a/src/Ryujinx.HLE/Switch.cs
+++ b/src/Ryujinx.HLE/Switch.cs
@@ -83,7 +83,7 @@ namespace Ryujinx.HLE
#pragma warning disable IDE0055 // Disable formatting
DirtyHacks = new DirtyHacks(Configuration.Hacks);
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver);
- Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), memoryAllocationFlags);
+ Memory = new MemoryBlock(Configuration.MemoryConfiguration.DramSize, memoryAllocationFlags);
Gpu = new GpuContext(Configuration.GpuRenderer, DirtyHacks);
Debugger = Configuration.EnableGdbStub ? new Debugger.Debugger(this, Configuration.GdbStubPort) : null;
System = new HOS.Horizon(this);
diff --git a/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator.cs b/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator.cs
index 35967d274..0ccc35fc8 100644
--- a/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator.cs
+++ b/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator.cs
@@ -52,7 +52,7 @@ namespace Ryujinx.Horizon.Bcat.Ipc
service = null;
}
- return resultCode.ToHorizonResult();
+ return resultCode.Horizon;
}
[CmifCommand(2)]
@@ -71,7 +71,7 @@ namespace Ryujinx.Horizon.Bcat.Ipc
service = null;
}
- return resultCode.ToHorizonResult();
+ return resultCode.Horizon;
}
public void Dispose()
diff --git a/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheDirectoryService.cs b/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheDirectoryService.cs
index 1559c833c..132453f05 100644
--- a/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheDirectoryService.cs
+++ b/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheDirectoryService.cs
@@ -22,19 +22,19 @@ namespace Ryujinx.Horizon.Bcat.Ipc
[CmifCommand(0)]
public Result Open(DirectoryName directoryName)
{
- return _libHacService.Get.Open(ref directoryName).ToHorizonResult();
+ return _libHacService.Get.Open(ref directoryName).Horizon;
}
[CmifCommand(1)]
public Result Read(out int entriesRead, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span entriesBuffer)
{
- return _libHacService.Get.Read(out entriesRead, entriesBuffer).ToHorizonResult();
+ return _libHacService.Get.Read(out entriesRead, entriesBuffer).Horizon;
}
[CmifCommand(2)]
public Result GetCount(out int count)
{
- return _libHacService.Get.GetCount(out count).ToHorizonResult();
+ return _libHacService.Get.GetCount(out count).Horizon;
}
public void Dispose()
diff --git a/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheFileService.cs b/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheFileService.cs
index bd5c418d9..cb6cc3159 100644
--- a/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheFileService.cs
+++ b/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheFileService.cs
@@ -22,25 +22,25 @@ namespace Ryujinx.Horizon.Bcat.Ipc
[CmifCommand(0)]
public Result Open(DirectoryName directoryName, FileName fileName)
{
- return _libHacService.Get.Open(ref directoryName, ref fileName).ToHorizonResult();
+ return _libHacService.Get.Open(ref directoryName, ref fileName).Horizon;
}
[CmifCommand(1)]
public Result Read(long offset, out long bytesRead, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span data)
{
- return _libHacService.Get.Read(out bytesRead, offset, data).ToHorizonResult();
+ return _libHacService.Get.Read(out bytesRead, offset, data).Horizon;
}
[CmifCommand(2)]
public Result GetSize(out long size)
{
- return _libHacService.Get.GetSize(out size).ToHorizonResult();
+ return _libHacService.Get.GetSize(out size).Horizon;
}
[CmifCommand(3)]
public Result GetDigest(out Digest digest)
{
- return _libHacService.Get.GetDigest(out digest).ToHorizonResult();
+ return _libHacService.Get.GetDigest(out digest).Horizon;
}
public void Dispose()
diff --git a/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheStorageService.cs b/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheStorageService.cs
index 356156fc1..b70d074d0 100644
--- a/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheStorageService.cs
+++ b/src/Ryujinx.Horizon/Bcat/Ipc/ServiceCreator/DeliveryCacheStorageService.cs
@@ -35,7 +35,7 @@ namespace Ryujinx.Horizon.Bcat.Ipc
service = null;
}
- return resultCode.ToHorizonResult();
+ return resultCode.Horizon;
}
[CmifCommand(1)]
@@ -54,13 +54,13 @@ namespace Ryujinx.Horizon.Bcat.Ipc
service = null;
}
- return resultCode.ToHorizonResult();
+ return resultCode.Horizon;
}
[CmifCommand(10)]
public Result EnumerateDeliveryCacheDirectory(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span directoryNames)
{
- return _libHacService.Get.EnumerateDeliveryCacheDirectory(out count, directoryNames).ToHorizonResult();
+ return _libHacService.Get.EnumerateDeliveryCacheDirectory(out count, directoryNames).Horizon;
}
public void Dispose()
diff --git a/src/Ryujinx.Horizon/LibHacResultExtensions.cs b/src/Ryujinx.Horizon/LibHacResultExtensions.cs
index 2abed197d..92c384141 100644
--- a/src/Ryujinx.Horizon/LibHacResultExtensions.cs
+++ b/src/Ryujinx.Horizon/LibHacResultExtensions.cs
@@ -4,9 +4,9 @@ namespace Ryujinx.Horizon
{
public static class LibHacResultExtensions
{
- public static Result ToHorizonResult(this LibHac.Result result)
+ extension(LibHac.Result libHacResult)
{
- return new Result((int)result.Module, (int)result.Description);
+ public Result Horizon => new((int)libHacResult.Module, (int)libHacResult.Description);
}
}
}
diff --git a/src/Ryujinx.Memory/Tracking/MultiRegionHandle.cs b/src/Ryujinx.Memory/Tracking/MultiRegionHandle.cs
index 20d2a07ef..fdaa87956 100644
--- a/src/Ryujinx.Memory/Tracking/MultiRegionHandle.cs
+++ b/src/Ryujinx.Memory/Tracking/MultiRegionHandle.cs
@@ -123,10 +123,7 @@ namespace Ryujinx.Memory.Tracking
Dirty = true;
}
- public IEnumerable GetHandles()
- {
- return _handles;
- }
+ public IEnumerable Handles => _handles;
public void ForceDirty(ulong address, ulong size)
{
diff --git a/src/Ryujinx.Tests.Memory/MultiRegionTrackingTests.cs b/src/Ryujinx.Tests.Memory/MultiRegionTrackingTests.cs
index b35de3a82..e878ff653 100644
--- a/src/Ryujinx.Tests.Memory/MultiRegionTrackingTests.cs
+++ b/src/Ryujinx.Tests.Memory/MultiRegionTrackingTests.cs
@@ -335,7 +335,7 @@ namespace Ryujinx.Tests.Memory
IEnumerable[] handleGroups =
[
- granular.GetHandles(),
+ granular.Handles,
singlePages,
doublePages
];
@@ -389,7 +389,7 @@ namespace Ryujinx.Tests.Memory
Assert.IsTrue(throws);
}
- IEnumerable combinedHandles = combined.GetHandles();
+ IEnumerable combinedHandles = combined.Handles;
Assert.AreEqual(handleGroups[0].ElementAt(0), combinedHandles.ElementAt(3));
Assert.AreEqual(handleGroups[0].ElementAt(1), combinedHandles.ElementAt(4));
diff --git a/src/Ryujinx/Headless/Options.cs b/src/Ryujinx/Headless/Options.cs
index 88c74eee5..382294cf7 100644
--- a/src/Ryujinx/Headless/Options.cs
+++ b/src/Ryujinx/Headless/Options.cs
@@ -59,10 +59,10 @@ namespace Ryujinx.Headless
DisableDockedMode = !configurationState.System.EnableDockedMode;
if (NeedsOverride(nameof(SystemLanguage)))
- SystemLanguage = configurationState.System.Language.Value.ToHLE();
+ SystemLanguage = configurationState.System.Language.Value.Horizon;
if (NeedsOverride(nameof(SystemRegion)))
- SystemRegion = configurationState.System.Region.Value.ToHLE();
+ SystemRegion = configurationState.System.Region.Value.Horizon;
if (NeedsOverride(nameof(SystemTimeZone)))
SystemTimeZone = configurationState.System.TimeZone;
diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs
index 407c3a556..7dcfdb838 100644
--- a/src/Ryujinx/Program.cs
+++ b/src/Ryujinx/Program.cs
@@ -296,16 +296,16 @@ namespace Ryujinx.Ava
// Check if region was overridden.
if (CommandLineState.OverrideSystemRegion is not null)
- if (Enum.TryParse(CommandLineState.OverrideSystemRegion, true, out HLE.HOS.SystemState.RegionCode result))
+ if (Enum.TryParse(CommandLineState.OverrideSystemRegion, true, out Region result))
{
- ConfigurationState.Instance.System.Region.Value = result.ToUI();
+ ConfigurationState.Instance.System.Region.Value = result;
}
//Check if language was overridden.
if (CommandLineState.OverrideSystemLanguage is not null)
- if (Enum.TryParse(CommandLineState.OverrideSystemLanguage, true, out HLE.HOS.SystemState.SystemLanguage result))
+ if (Enum.TryParse(CommandLineState.OverrideSystemLanguage, true, out Language result))
{
- ConfigurationState.Instance.System.Language.Value = result.ToUI();
+ ConfigurationState.Instance.System.Language.Value = result;
}
// Check if hardware-acceleration was overridden.
diff --git a/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs b/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs
index 405400b81..2b4c8f991 100644
--- a/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs
+++ b/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs
@@ -916,8 +916,8 @@ namespace Ryujinx.Ava.Systems.Configuration
public HleConfiguration CreateHleConfiguration() =>
new(
System.DramSize,
- System.Language.Value.ToHLE(),
- System.Region.Value.ToHLE(),
+ System.Language.Value.Horizon,
+ System.Region.Value.Horizon,
Graphics.VSyncMode,
System.EnableDockedMode,
System.EnablePtc,
diff --git a/src/Ryujinx/Systems/Configuration/System/Language.cs b/src/Ryujinx/Systems/Configuration/System/Language.cs
index ff1476b73..3087653e9 100644
--- a/src/Ryujinx/Systems/Configuration/System/Language.cs
+++ b/src/Ryujinx/Systems/Configuration/System/Language.cs
@@ -1,4 +1,5 @@
using Ryujinx.Common.Utilities;
+using Ryujinx.HLE.HOS.SystemState;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Systems.Configuration.System
@@ -28,10 +29,14 @@ namespace Ryujinx.Ava.Systems.Configuration.System
public static class LanguageEnumHelper
{
- public static Language ToUI(this HLE.HOS.SystemState.SystemLanguage hleLanguage)
- => (Language)hleLanguage;
+ extension(SystemLanguage hle)
+ {
+ public Language Ui => (Language)hle;
+ }
- public static HLE.HOS.SystemState.SystemLanguage ToHLE(this Language uiLanguage)
- => (HLE.HOS.SystemState.SystemLanguage)uiLanguage;
+ extension(Language ui)
+ {
+ public SystemLanguage Horizon => (SystemLanguage)ui;
+ }
}
}
diff --git a/src/Ryujinx/Systems/Configuration/System/Region.cs b/src/Ryujinx/Systems/Configuration/System/Region.cs
index 0c86093cc..2ba657876 100644
--- a/src/Ryujinx/Systems/Configuration/System/Region.cs
+++ b/src/Ryujinx/Systems/Configuration/System/Region.cs
@@ -1,4 +1,5 @@
using Ryujinx.Common.Utilities;
+using Ryujinx.HLE.HOS.SystemState;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Systems.Configuration.System
@@ -17,10 +18,14 @@ namespace Ryujinx.Ava.Systems.Configuration.System
public static class RegionEnumHelper
{
- public static Region ToUI(this HLE.HOS.SystemState.RegionCode hleRegion)
- => (Region)hleRegion;
+ extension(RegionCode hle)
+ {
+ public Region Ui => (Region)hle;
+ }
- public static HLE.HOS.SystemState.RegionCode ToHLE(this Region uiRegion)
- => (HLE.HOS.SystemState.RegionCode)uiRegion;
+ extension(Region ui)
+ {
+ public RegionCode Horizon => (RegionCode)ui;
+ }
}
}
diff --git a/src/Ryujinx/UI/Helpers/Converters/XCITrimmerFileStatusDetailConverter.cs b/src/Ryujinx/UI/Helpers/Converters/XCITrimmerFileStatusDetailConverter.cs
index b83fe485d..34734661b 100644
--- a/src/Ryujinx/UI/Helpers/Converters/XCITrimmerFileStatusDetailConverter.cs
+++ b/src/Ryujinx/UI/Helpers/Converters/XCITrimmerFileStatusDetailConverter.cs
@@ -29,9 +29,11 @@ namespace Ryujinx.Ava.UI.Helpers
return null;
}
- return app.PercentageProgress != null ? null :
- app.ProcessingOutcome is not OperationOutcome.Successful and not OperationOutcome.Undetermined ? app.ProcessingOutcome.ToLocalisedText() :
- null;
+ return app.PercentageProgress != null
+ ? null
+ : app.ProcessingOutcome is not OperationOutcome.Successful and not OperationOutcome.Undetermined
+ ? app.ProcessingOutcome.LocalizedText
+ : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/src/Ryujinx/UI/Helpers/XCITrimmerOperationOutcomeHelper.cs b/src/Ryujinx/UI/Helpers/XCITrimmerOperationOutcomeHelper.cs
index 1a0e126c8..d58056469 100644
--- a/src/Ryujinx/UI/Helpers/XCITrimmerOperationOutcomeHelper.cs
+++ b/src/Ryujinx/UI/Helpers/XCITrimmerOperationOutcomeHelper.cs
@@ -5,32 +5,23 @@ namespace Ryujinx.Ava.UI.Helpers
{
public static class XCIFileTrimmerOperationOutcomeExtensions
{
- public static string ToLocalisedText(this OperationOutcome operationOutcome)
+ extension(OperationOutcome opOutcome)
{
- switch (operationOutcome)
+ public string LocalizedText => opOutcome switch
{
- case OperationOutcome.NoTrimNecessary:
- return LocaleManager.Instance[LocaleKeys.TrimXCIFileNoTrimNecessary];
- case OperationOutcome.NoUntrimPossible:
- return LocaleManager.Instance[LocaleKeys.TrimXCIFileNoUntrimPossible];
- case OperationOutcome.ReadOnlyFileCannotFix:
- return LocaleManager.Instance[LocaleKeys.TrimXCIFileReadOnlyFileCannotFix];
- case OperationOutcome.FreeSpaceCheckFailed:
- return LocaleManager.Instance[LocaleKeys.TrimXCIFileFreeSpaceCheckFailed];
- case OperationOutcome.InvalidXCIFile:
- return LocaleManager.Instance[LocaleKeys.TrimXCIFileInvalidXCIFile];
- case OperationOutcome.FileIOWriteError:
- return LocaleManager.Instance[LocaleKeys.TrimXCIFileFileIOWriteError];
- case OperationOutcome.FileSizeChanged:
- return LocaleManager.Instance[LocaleKeys.TrimXCIFileFileSizeChanged];
- case OperationOutcome.Cancelled:
- return LocaleManager.Instance[LocaleKeys.TrimXCIFileCancelled];
- case OperationOutcome.Undetermined:
- return LocaleManager.Instance[LocaleKeys.TrimXCIFileFileUndertermined];
- case OperationOutcome.Successful:
- default:
- return null;
- }
+ OperationOutcome.NoTrimNecessary => LocaleManager.Instance[LocaleKeys.TrimXCIFileNoTrimNecessary],
+ OperationOutcome.NoUntrimPossible => LocaleManager.Instance[LocaleKeys.TrimXCIFileNoUntrimPossible],
+ OperationOutcome.ReadOnlyFileCannotFix => LocaleManager.Instance[
+ LocaleKeys.TrimXCIFileReadOnlyFileCannotFix],
+ OperationOutcome.FreeSpaceCheckFailed => LocaleManager.Instance[
+ LocaleKeys.TrimXCIFileFreeSpaceCheckFailed],
+ OperationOutcome.InvalidXCIFile => LocaleManager.Instance[LocaleKeys.TrimXCIFileInvalidXCIFile],
+ OperationOutcome.FileIOWriteError => LocaleManager.Instance[LocaleKeys.TrimXCIFileFileIOWriteError],
+ OperationOutcome.FileSizeChanged => LocaleManager.Instance[LocaleKeys.TrimXCIFileFileSizeChanged],
+ OperationOutcome.Cancelled => LocaleManager.Instance[LocaleKeys.TrimXCIFileCancelled],
+ OperationOutcome.Undetermined => LocaleManager.Instance[LocaleKeys.TrimXCIFileFileUndertermined],
+ _ => null
+ };
}
}
}
diff --git a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs
index 727294992..47a99d886 100644
--- a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs
@@ -11,13 +11,17 @@ namespace Ryujinx.Ava.UI.ViewModels
{
public partial class AboutWindowViewModel : BaseModel, IDisposable
{
- [ObservableProperty] private Bitmap _gitLabLogo;
- [ObservableProperty] private Bitmap _discordLogo;
- [ObservableProperty] private string _version;
+ [ObservableProperty] public partial Bitmap GitLabLogo { get; set; }
- public string Developers => "GreemDev, LotP";
+ [ObservableProperty] public partial Bitmap DiscordLogo { get; set; }
- public string FormerDevelopers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz");
+ [ObservableProperty] public partial string Version { get; set; }
+
+ public static string Developers => "GreemDev, LotP";
+
+ public static string FormerDevelopers => LocaleManager.Instance.UpdateAndGetDynamicValue(
+ LocaleKeys.AboutPageDeveloperListMore,
+ "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz");
public AboutWindowViewModel()
{
@@ -36,7 +40,8 @@ namespace Ryujinx.Ava.UI.ViewModels
private void UpdateLogoTheme(string theme)
{
- bool isDarkTheme = theme == "Dark" || (theme == "Auto" && RyujinxApp.DetectSystemTheme() == ThemeVariant.Dark);
+ bool isDarkTheme = theme == "Dark" ||
+ (theme == "Auto" && RyujinxApp.DetectSystemTheme() == ThemeVariant.Dark);
string themeName = isDarkTheme ? "Dark" : "Light";
diff --git a/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs
index 0ba071475..053972c2c 100644
--- a/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs
@@ -2,6 +2,7 @@ using Avalonia;
using Avalonia.Collections;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
+using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models.Amiibo;
using Ryujinx.Ava.UI.Helpers;
@@ -23,7 +24,7 @@ using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.ViewModels
{
- public class AmiiboWindowViewModel : BaseModel, IDisposable
+ public partial class AmiiboWindowViewModel : BaseModel, IDisposable
{
// ReSharper disable once InconsistentNaming
private static bool _cachedUseRandomUuid;
@@ -36,17 +37,13 @@ namespace Ryujinx.Ava.UI.ViewModels
private readonly HttpClient _httpClient;
private readonly AmiiboWindow _owner;
- private Bitmap _amiiboImage;
private List _amiiboList;
private AvaloniaList _amiibos;
private ObservableCollection _amiiboSeries;
private int _amiiboSelectedIndex;
private int _seriesSelectedIndex;
- private bool _enableScanning;
private bool _showAllAmiibo;
- private bool _useRandomUuid = _cachedUseRandomUuid;
- private string _usage;
private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@@ -83,14 +80,14 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool UseRandomUuid
{
- get => _useRandomUuid;
+ get;
set
{
- _cachedUseRandomUuid = _useRandomUuid = value;
+ _cachedUseRandomUuid = field = value;
OnPropertyChanged();
}
- }
+ } = _cachedUseRandomUuid;
public bool ShowAllAmiibo
{
@@ -154,38 +151,14 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
- public Bitmap AmiiboImage
- {
- get => _amiiboImage;
- set
- {
- _amiiboImage = value;
+ [ObservableProperty]
+ public partial Bitmap AmiiboImage { get; set; }
- OnPropertyChanged();
- }
- }
+ [ObservableProperty]
+ public partial string Usage { get; set; }
- public string Usage
- {
- get => _usage;
- set
- {
- _usage = value;
-
- OnPropertyChanged();
- }
- }
-
- public bool EnableScanning
- {
- get => _enableScanning;
- set
- {
- _enableScanning = value;
-
- OnPropertyChanged();
- }
- }
+ [ObservableProperty]
+ public partial bool EnableScanning { get; set; }
public void Scan()
{
diff --git a/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs b/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs
index 643614d6e..b280c96c9 100644
--- a/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs
@@ -7,14 +7,16 @@ namespace Ryujinx.Ava.UI.ViewModels
{
public partial class DlcSelectViewModel : BaseModel
{
- [ObservableProperty] private DownloadableContentModel[] _dlcs;
+ [ObservableProperty]
+ public partial DownloadableContentModel[] Dlcs { get; set; }
#nullable enable
- [ObservableProperty] private DownloadableContentModel? _selectedDlc;
+ [ObservableProperty]
+ public partial DownloadableContentModel? SelectedDlc { get; set; }
#nullable disable
public DlcSelectViewModel(ulong titleId, ApplicationLibrary appLibrary)
{
- _dlcs = appLibrary.FindDlcsFor(titleId)
+ Dlcs = appLibrary.FindDlcsFor(titleId)
.OrderBy(it => it.IsBundled ? 0 : 1)
.ThenBy(it => it.TitleId)
.ToArray();
diff --git a/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs
index c048b481c..39e53184f 100644
--- a/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs
@@ -19,10 +19,14 @@ namespace Ryujinx.Ava.UI.ViewModels
public partial class DownloadableContentManagerViewModel : BaseModel
{
private readonly ApplicationLibrary _applicationLibrary;
- private AvaloniaList _downloadableContents = [];
- [ObservableProperty] private AvaloniaList _selectedDownloadableContents = [];
- [ObservableProperty] private AvaloniaList _views = [];
- [ObservableProperty] private bool _showBundledContentNotice = false;
+ [ObservableProperty]
+ public partial AvaloniaList SelectedDownloadableContents { get; set; } = [];
+
+ [ObservableProperty]
+ public partial AvaloniaList Views { get; set; } = [];
+
+ [ObservableProperty]
+ public partial bool ShowBundledContentNotice { get; set; } = false;
private string _search;
private readonly ApplicationData _applicationData;
@@ -30,15 +34,15 @@ namespace Ryujinx.Ava.UI.ViewModels
public AvaloniaList DownloadableContents
{
- get => _downloadableContents;
+ get;
set
{
- _downloadableContents = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(UpdateCount));
Sort();
}
- }
+ } = [];
public string Search
{
@@ -51,10 +55,7 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
- public string UpdateCount
- {
- get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count);
- }
+ public string UpdateCount => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count);
public DownloadableContentManagerViewModel(ApplicationLibrary applicationLibrary, ApplicationData applicationData)
{
diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs
index 61d3ffd59..2949b69a8 100644
--- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs
@@ -4,55 +4,50 @@ using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Views.Input;
using Ryujinx.Common.Utilities;
using Ryujinx.UI.Views.Input;
-using System.Drawing;
namespace Ryujinx.Ava.UI.ViewModels.Input
{
public partial class ControllerInputViewModel : BaseModel
{
- private GamepadInputConfig _config;
public GamepadInputConfig Config
{
- get => _config;
+ get;
set
{
- _config = value;
+ field = value;
OnPropertyChanged();
}
}
- private StickVisualizer _visualizer;
public StickVisualizer Visualizer
{
- get => _visualizer;
+ get;
set
{
- _visualizer = value;
+ field = value;
OnPropertyChanged();
}
}
- private bool _isLeft;
public bool IsLeft
{
- get => _isLeft;
+ get;
set
{
- _isLeft = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
- private bool _isRight;
public bool IsRight
{
- get => _isRight;
+ get;
set
{
- _isRight = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
@@ -60,8 +55,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool HasSides => IsLeft ^ IsRight;
- [ObservableProperty] private SvgImage _image;
-
+ [ObservableProperty]
+ public partial SvgImage Image { get; set; }
public InputViewModel ParentModel { get; }
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config, StickVisualizer visualizer)
@@ -75,7 +70,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
if (args.PropertyName is nameof(Config.UseRainbowLed))
{
if (Config is { UseRainbowLed: true, TurnOffLed: false, EnableLedChanging: true })
- Rainbow.Updated += (ref Color color) => ParentModel.SelectedGamepad.SetLed((uint)color.ToArgb());
+ Rainbow.Updated += (ref color) => ParentModel.SelectedGamepad.SetLed((uint)color.ToArgb());
else
{
Rainbow.Reset();
diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
index c89846dc4..289dc0e9c 100644
--- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs
@@ -48,36 +48,41 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private int _controller;
private string _controllerImage;
private int _device;
- private object _configViewModel;
private bool _isChangeTrackingActive;
- private string _chosenProfile;
- [ObservableProperty] private bool _isModified;
- [ObservableProperty] private string _profileName;
- [ObservableProperty] private bool _notificationIsVisible; // Automatically call the NotificationView property with OnPropertyChanged()
- [ObservableProperty] private string _notificationText; // Automatically call the NotificationText property with OnPropertyChanged()
+ [ObservableProperty]
+ public partial bool IsModified { get; set; }
+
+ [ObservableProperty]
+ public partial string ProfileName { get; set; }
+
+ [ObservableProperty]
+ public partial bool NotificationIsVisible { get; set; } // Automatically call the NotificationView property with OnPropertyChanged()
+
+ [ObservableProperty]
+ public partial string NotificationText { get; set; } // Automatically call the NotificationText property with OnPropertyChanged()
+
private bool _isLoaded;
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public IGamepadDriver AvaloniaKeyboardDriver { get; }
- private IGamepad _selectedGamepad;
-
public IGamepad SelectedGamepad
{
- get => _selectedGamepad;
+ get;
private set
{
Rainbow.Reset();
- _selectedGamepad = value;
+ field = value;
if (ConfigViewModel is ControllerInputViewModel { Config.UseRainbowLed: true })
- Rainbow.Updated += (ref Color color) => _selectedGamepad.SetLed((uint)color.ToArgb());
+ Rainbow.Updated += (ref Color color) => field.SetLed((uint)color.ToArgb());
OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed));
}
}
+
public StickVisualizer VisualStick { get; private set; }
public ObservableCollection PlayerIndexes { get; set; }
@@ -99,15 +104,15 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense");
public event Action NotifyChangesEvent;
-
+
public string ChosenProfile
{
- get => _chosenProfile;
+ get;
set
{
// When you select a profile, the settings from the profile will be applied.
// To save the settings, you still need to click the apply button
- _chosenProfile = value;
+ field = value;
LoadProfile();
OnPropertyChanged();
}
@@ -115,10 +120,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public object ConfigViewModel
{
- get => _configViewModel;
+ get;
set
{
- _configViewModel = value;
+ field = value;
VisualStick.UpdateConfig(value);
diff --git a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs
index bab8db7ce..178e2c955 100644
--- a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs
@@ -6,49 +6,45 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
public partial class KeyboardInputViewModel : BaseModel
{
- private KeyboardInputConfig _config;
public KeyboardInputConfig Config
{
- get => _config;
+ get;
set
{
- _config = value;
+ field = value;
OnPropertyChanged();
}
}
- private StickVisualizer _visualizer;
public StickVisualizer Visualizer
{
- get => _visualizer;
+ get;
set
{
- _visualizer = value;
+ field = value;
OnPropertyChanged();
}
}
- private bool _isLeft;
public bool IsLeft
{
- get => _isLeft;
+ get;
set
{
- _isLeft = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
}
- private bool _isRight;
public bool IsRight
{
- get => _isRight;
+ get;
set
{
- _isRight = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(HasSides));
}
@@ -56,7 +52,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool HasSides => IsLeft ^ IsRight;
- [ObservableProperty] private SvgImage _image;
+ [ObservableProperty]
+ public partial SvgImage Image { get; set; }
public readonly InputViewModel ParentModel;
diff --git a/src/Ryujinx/UI/ViewModels/Input/LedInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/LedInputViewModel.cs
index 71c404c21..516b892b5 100644
--- a/src/Ryujinx/UI/ViewModels/Input/LedInputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/LedInputViewModel.cs
@@ -23,8 +23,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
ParentModel.SelectedGamepad.SetLed(LedColor.ToUInt32());
});
- [ObservableProperty] private bool _enableLedChanging;
- [ObservableProperty] private Color _ledColor;
+ [ObservableProperty]
+ public partial bool EnableLedChanging { get; set; }
+
+ [ObservableProperty]
+ public partial Color LedColor { get; set; }
public string RainbowSpeedText => RainbowSpeed.ToString(CultureInfo.CurrentCulture).Truncate(4, string.Empty);
@@ -41,27 +44,23 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed;
- private bool _turnOffLed;
-
public bool TurnOffLed
{
- get => _turnOffLed;
+ get;
set
{
- _turnOffLed = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowLedColorPicker));
}
}
- private bool _useRainbowLed;
-
public bool UseRainbowLed
{
- get => _useRainbowLed;
+ get;
set
{
- _useRainbowLed = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowLedColorPicker));
}
diff --git a/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs
index ba8686831..ad9a70eaa 100644
--- a/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs
@@ -4,20 +4,28 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
public partial class MotionInputViewModel : BaseModel
{
- [ObservableProperty] private int _slot;
+ [ObservableProperty]
+ public partial int Slot { get; set; }
- [ObservableProperty] private int _altSlot;
+ [ObservableProperty]
+ public partial int AltSlot { get; set; }
- [ObservableProperty] private string _dsuServerHost;
+ [ObservableProperty]
+ public partial string DsuServerHost { get; set; }
- [ObservableProperty] private int _dsuServerPort;
+ [ObservableProperty]
+ public partial int DsuServerPort { get; set; }
- [ObservableProperty] private bool _mirrorInput;
+ [ObservableProperty]
+ public partial bool MirrorInput { get; set; }
- [ObservableProperty] private int _sensitivity;
+ [ObservableProperty]
+ public partial int Sensitivity { get; set; }
- [ObservableProperty] private double _gyroDeadzone;
+ [ObservableProperty]
+ public partial double GyroDeadzone { get; set; }
- [ObservableProperty] private bool _enableCemuHookMotion;
+ [ObservableProperty]
+ public partial bool EnableCemuHookMotion { get; set; }
}
}
diff --git a/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs
index c4158fced..e2323f567 100644
--- a/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs
@@ -4,8 +4,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
public partial class RumbleInputViewModel : BaseModel
{
- [ObservableProperty] private float _strongRumble;
+ [ObservableProperty]
+ public partial float StrongRumble { get; set; }
- [ObservableProperty] private float _weakRumble;
+ [ObservableProperty]
+ public partial float WeakRumble { get; set; }
}
}
diff --git a/src/Ryujinx/UI/ViewModels/LdnGamesListViewModel.cs b/src/Ryujinx/UI/ViewModels/LdnGamesListViewModel.cs
index cdce9262d..91ebccabb 100644
--- a/src/Ryujinx/UI/ViewModels/LdnGamesListViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/LdnGamesListViewModel.cs
@@ -91,10 +91,8 @@ namespace Ryujinx.Ava.UI.ViewModels
OnPropertyChanged(nameof(VisibleEntries));
}
- [ObservableProperty] private bool _isRefreshing;
- private bool _onlyShowForOwnedGames;
- private bool _onlyShowPublicGames = true;
- private bool _onlyShowJoinableGames = true;
+ [ObservableProperty]
+ public partial bool IsRefreshing { get; set; }
public async Task RefreshAsync()
{
@@ -109,12 +107,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool OnlyShowForOwnedGames
{
- get => _onlyShowForOwnedGames;
+ get;
set
{
OnPropertyChanging();
OnPropertyChanging(nameof(VisibleEntries));
- _onlyShowForOwnedGames = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(VisibleEntries));
}
@@ -122,29 +120,29 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool OnlyShowPublicGames
{
- get => _onlyShowPublicGames;
+ get;
set
{
OnPropertyChanging();
OnPropertyChanging(nameof(VisibleEntries));
- _onlyShowPublicGames = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(VisibleEntries));
}
- }
+ } = true;
public bool OnlyShowJoinableGames
{
- get => _onlyShowJoinableGames;
+ get;
set
{
OnPropertyChanging();
OnPropertyChanging(nameof(VisibleEntries));
- _onlyShowJoinableGames = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(VisibleEntries));
}
- }
+ } = true;
public void NameSorting(int nameSort = 0)
diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs
index b665f23c9..2236b27f6 100644
--- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs
@@ -64,55 +64,101 @@ namespace Ryujinx.Ava.UI.ViewModels
public partial class MainWindowViewModel : BaseModel
{
private const int HotKeyPressDelayMs = 500;
+
private delegate int LoadContentFromFolderDelegate(List dirs, out int numRemoved);
- [ObservableProperty] private ObservableCollectionExtended _applications;
- [ObservableProperty] private string _aspectRatioStatusText;
- [ObservableProperty] private string _loadHeading;
- [ObservableProperty] private string _cacheLoadStatus;
- [ObservableProperty] private string _dockedStatusText;
- [ObservableProperty] private string _fifoStatusText;
- [ObservableProperty] private string _gameStatusText;
- [ObservableProperty] private string _volumeStatusText;
- [ObservableProperty] private string _gpuNameText;
- [ObservableProperty] private string _backendText;
- [ObservableProperty] private string _shaderCountText;
- [ObservableProperty] private bool _showShaderCompilationHint;
- [ObservableProperty] private bool _isFullScreen;
- [ObservableProperty] private int _progressMaximum;
- [ObservableProperty] private int _progressValue;
- [ObservableProperty] private bool _showMenuAndStatusBar = true;
- [ObservableProperty] private bool _showStatusSeparator;
- [ObservableProperty] private Brush _progressBarForegroundColor;
- [ObservableProperty] private Brush _progressBarBackgroundColor;
- [ObservableProperty] private Brush _vSyncModeColor;
-#nullable enable
- [ObservableProperty] private byte[]? _selectedIcon;
-#nullable disable
- [ObservableProperty] private int _statusBarProgressMaximum;
- [ObservableProperty] private int _statusBarProgressValue;
- [ObservableProperty] private string _statusBarProgressStatusText;
- [ObservableProperty] private bool _statusBarProgressStatusVisible;
- [ObservableProperty] private bool _isPaused;
- [ObservableProperty] private bool _isLoadingIndeterminate = true;
- [ObservableProperty] private bool _showAll;
- [ObservableProperty] private string _lastScannedAmiiboId;
+ [ObservableProperty] public partial ObservableCollectionExtended Applications { get; set; }
+
+ [ObservableProperty] public partial string AspectRatioStatusText { get; set; }
+
+ [ObservableProperty] public partial string LoadHeading { get; set; }
+
+ [ObservableProperty] public partial string CacheLoadStatus { get; set; }
+
+ [ObservableProperty] public partial string DockedStatusText { get; set; }
+
+ [ObservableProperty] public partial string FifoStatusText { get; set; }
+
+ [ObservableProperty] public partial string GameStatusText { get; set; }
+
+ [ObservableProperty] public partial string VolumeStatusText { get; set; }
+
+ [ObservableProperty] public partial string GpuNameText { get; set; }
+
+ [ObservableProperty] public partial string BackendText { get; set; }
+
+ [ObservableProperty] public partial string ShaderCountText { get; set; }
+
+ [ObservableProperty] public partial bool ShowShaderCompilationHint { get; set; }
+
+ [ObservableProperty] public partial bool IsFullScreen { get; set; }
+
+ [ObservableProperty] public partial int ProgressMaximum { get; set; }
+
+ [ObservableProperty] public partial int ProgressValue { get; set; }
+
+ [ObservableProperty] public partial bool ShowMenuAndStatusBar { get; set; } = true;
+
+ [ObservableProperty] public partial bool ShowStatusSeparator { get; set; }
+
+ [ObservableProperty] public partial Brush ProgressBarForegroundColor { get; set; }
+
+ [ObservableProperty] public partial Brush ProgressBarBackgroundColor { get; set; }
+
+#pragma warning disable MVVMTK0042 // Must stay a normal observable field declaration since this is used as an out parameter target
[ObservableProperty] private ReadOnlyObservableCollection _appsObservableList;
- [ObservableProperty] private long _lastFullscreenToggle = Environment.TickCount64;
- [ObservableProperty] private bool _showContent = true;
- [ObservableProperty] private float _volumeBeforeMute;
- [ObservableProperty] private bool _areMimeTypesRegistered = FileAssociationHelper.AreMimeTypesRegistered;
- [ObservableProperty] private Cursor _cursor;
- [ObservableProperty] private string _title;
- [ObservableProperty] private WindowState _windowState;
- [ObservableProperty] private double _windowWidth;
- [ObservableProperty] private double _windowHeight;
- [ObservableProperty] private bool _isActive;
- [ObservableProperty] private bool _isSubMenuOpen;
- [ObservableProperty] private ApplicationContextMenu _listAppContextMenu;
- [ObservableProperty] private ApplicationContextMenu _gridAppContextMenu;
- [ObservableProperty] private bool _isRyuLdnEnabled;
- [ObservableProperty] private bool _updateAvailable;
+#pragma warning restore MVVMTK0042
+
+ [ObservableProperty] public partial Brush VSyncModeColor { get; set; }
+#nullable enable
+ [ObservableProperty] public partial byte[]? SelectedIcon { get; set; }
+#nullable disable
+ [ObservableProperty] public partial int StatusBarProgressMaximum { get; set; }
+
+ [ObservableProperty] public partial int StatusBarProgressValue { get; set; }
+
+ [ObservableProperty] public partial string StatusBarProgressStatusText { get; set; }
+
+ [ObservableProperty] public partial bool StatusBarProgressStatusVisible { get; set; }
+
+ [ObservableProperty] public partial bool IsPaused { get; set; }
+
+ [ObservableProperty] public partial bool IsLoadingIndeterminate { get; set; } = true;
+
+ [ObservableProperty] public partial bool ShowAll { get; set; }
+
+ [ObservableProperty] public partial string LastScannedAmiiboId { get; set; }
+
+ [ObservableProperty]
+ public partial long LastFullscreenToggle { get; set; } = Environment.TickCount64;
+ [ObservableProperty] public partial bool ShowContent { get; set; } = true;
+
+ [ObservableProperty] public partial float VolumeBeforeMute { get; set; }
+
+ [ObservableProperty]
+ public partial bool AreMimeTypesRegistered { get; set; } = FileAssociationHelper.AreMimeTypesRegistered;
+
+ [ObservableProperty] public partial Cursor Cursor { get; set; }
+
+ [ObservableProperty] public partial string Title { get; set; }
+
+ [ObservableProperty] public partial WindowState WindowState { get; set; }
+
+ [ObservableProperty] public partial double WindowWidth { get; set; }
+
+ [ObservableProperty] public partial double WindowHeight { get; set; }
+
+ [ObservableProperty] public partial bool IsActive { get; set; }
+
+ [ObservableProperty] public partial bool IsSubMenuOpen { get; set; }
+
+ [ObservableProperty] public partial ApplicationContextMenu ListAppContextMenu { get; set; }
+
+ [ObservableProperty] public partial ApplicationContextMenu GridAppContextMenu { get; set; }
+
+ [ObservableProperty] public partial bool IsRyuLdnEnabled { get; set; }
+
+ [ObservableProperty] public partial bool UpdateAvailable { get; set; }
public static AsyncRelayCommand UpdateCommand { get; } = Commands.Create(async () =>
{
@@ -120,27 +166,17 @@ namespace Ryujinx.Ava.UI.ViewModels
await Updater.BeginUpdateAsync(true);
});
- private bool _showTotalTimePlayed;
- private bool _showLoadProgress;
private bool _isGameRunning;
- private bool _isAmiiboRequested;
- private bool _isAmiiboBinRequested;
private string _searchText;
private Timer _searchTimer;
- private string _vSyncModeText;
private string _showUiKey = "F4";
private string _pauseKey = "F5";
private string _screenshotKey = "F8";
private float _volume;
- private bool _isAppletMenuActive;
- private bool _statusBarVisible;
- private bool _canUpdate = true;
private ApplicationData _currentApplicationData;
private readonly AutoResetEvent _rendererWaitEvent;
private int _customVSyncInterval;
private int _customVSyncIntervalPercentageProxy;
- private ApplicationData _listSelectedApplication;
- private ApplicationData _gridSelectedApplication;
// Key is Title ID
///
@@ -267,20 +303,20 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool CanUpdate
{
- get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate();
+ get => field && EnableNonGameRunningControls && Updater.CanUpdate();
set
{
- _canUpdate = value;
+ field = value;
OnPropertyChanged();
}
- }
+ } = true;
public bool StatusBarVisible
{
- get => _statusBarVisible && EnableNonGameRunningControls;
+ get => field && EnableNonGameRunningControls;
set
{
- _statusBarVisible = value;
+ field = value;
OnPropertyChanged();
}
@@ -312,20 +348,21 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsAmiiboRequested
{
- get => _isAmiiboRequested && _isGameRunning;
+ get => field && _isGameRunning;
set
{
- _isAmiiboRequested = value;
+ field = value;
OnPropertyChanged();
}
}
+
public bool IsAmiiboBinRequested
{
- get => _isAmiiboBinRequested && _isGameRunning;
+ get => field && _isGameRunning;
set
{
- _isAmiiboBinRequested = value;
+ field = value;
OnPropertyChanged();
}
@@ -335,10 +372,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool ShowLoadProgress
{
- get => _showLoadProgress;
+ get;
set
{
- _showLoadProgress = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowFirmwareStatus));
@@ -360,24 +397,24 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool ShowTotalTimePlayed
{
- get => _showTotalTimePlayed && EnableNonGameRunningControls;
+ get => field && EnableNonGameRunningControls;
set
{
- _showTotalTimePlayed = value;
+ field = value;
OnPropertyChanged();
}
}
public ApplicationData ListSelectedApplication
{
- get => _listSelectedApplication;
+ get;
set
{
- _listSelectedApplication = value;
+ field = value;
- if (_listSelectedApplication != null && ListAppContextMenu == null)
+ if (field != null && ListAppContextMenu == null)
ListAppContextMenu = new ApplicationContextMenu();
- else if (_listSelectedApplication == null && ListAppContextMenu != null)
+ else if (field == null && ListAppContextMenu != null)
ListAppContextMenu = null!;
OnPropertyChanged();
@@ -386,14 +423,14 @@ namespace Ryujinx.Ava.UI.ViewModels
public ApplicationData GridSelectedApplication
{
- get => _gridSelectedApplication;
+ get;
set
{
- _gridSelectedApplication = value;
+ field = value;
- if (_gridSelectedApplication != null && GridAppContextMenu == null)
+ if (field != null && GridAppContextMenu == null)
GridAppContextMenu = new ApplicationContextMenu();
- else if (_gridSelectedApplication == null && GridAppContextMenu != null)
+ else if (field == null && GridAppContextMenu != null)
GridAppContextMenu = null!;
OnPropertyChanged();
@@ -422,13 +459,18 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool HasDlc => ApplicationLibrary.HasDlcs(SelectedApplication.Id);
- public bool OpenUserSaveDirectoryEnabled => SelectedApplication.HasControlHolder && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
+ public bool OpenUserSaveDirectoryEnabled => SelectedApplication.HasControlHolder &&
+ SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
- public bool OpenDeviceSaveDirectoryEnabled => SelectedApplication.HasControlHolder && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
+ public bool OpenDeviceSaveDirectoryEnabled => SelectedApplication.HasControlHolder &&
+ SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
- public bool TrimXCIEnabled => XCIFileTrimmer.CanTrim(SelectedApplication.Path, new XCITrimmerLog.MainWindow(this));
+ public bool TrimXCIEnabled =>
+ XCIFileTrimmer.CanTrim(SelectedApplication.Path, new XCITrimmerLog.MainWindow(this));
- public bool OpenBcatSaveDirectoryEnabled => SelectedApplication.HasControlHolder && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
+ public bool OpenBcatSaveDirectoryEnabled => SelectedApplication.HasControlHolder &&
+ SelectedApplication.ControlHolder.Value
+ .BcatDeliveryCacheStorageSize > 0;
public bool ShowCustomVSyncIntervalPicker
=> _isGameRunning && AppHost.Device.VSyncMode == VSyncMode.Custom;
@@ -466,7 +508,6 @@ namespace Ryujinx.Ava.UI.ViewModels
}
set
{
-
}
}
@@ -492,10 +533,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public string VSyncModeText
{
- get => _vSyncModeText;
+ get;
set
{
- _vSyncModeText = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowCustomVSyncIntervalPicker));
@@ -524,10 +565,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsAppletMenuActive
{
- get => _isAppletMenuActive && EnableNonGameRunningControls;
+ get => field && EnableNonGameRunningControls;
set
{
- _isAppletMenuActive = value;
+ field = value;
OnPropertyChanged();
}
@@ -799,7 +840,8 @@ namespace Ryujinx.Ava.UI.ViewModels
#region PrivateMethods
- private static SortExpressionComparer CreateComparer(bool ascending, Func selector) =>
+ private static SortExpressionComparer CreateComparer(bool ascending,
+ Func selector) =>
ascending
? SortExpressionComparer.Ascending(selector)
: SortExpressionComparer.Descending(selector);
@@ -808,15 +850,15 @@ namespace Ryujinx.Ava.UI.ViewModels
=> SortMode switch
{
#pragma warning disable IDE0055 // Disable formatting
- ApplicationSort.Title => CreateComparer(IsAscending, app => app.Name),
- ApplicationSort.Developer => CreateComparer(IsAscending, app => app.Developer),
- ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending),
+ ApplicationSort.Title => CreateComparer(IsAscending, app => app.Name),
+ ApplicationSort.Developer => CreateComparer(IsAscending, app => app.Developer),
+ ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending),
ApplicationSort.TotalTimePlayed => new TimePlayedSortComparer(IsAscending),
- ApplicationSort.FileType => CreateComparer(IsAscending, app => app.FileExtension),
- ApplicationSort.FileSize => CreateComparer(IsAscending, app => app.FileSize),
- ApplicationSort.Path => CreateComparer(IsAscending, app => app.Path),
- ApplicationSort.Favorite => CreateComparer(IsAscending, app => new AppListFavoriteComparable(app)),
- ApplicationSort.TitleId => CreateComparer(IsAscending, app => app.Id),
+ ApplicationSort.FileType => CreateComparer(IsAscending, app => app.FileExtension),
+ ApplicationSort.FileSize => CreateComparer(IsAscending, app => app.FileSize),
+ ApplicationSort.Path => CreateComparer(IsAscending, app => app.Path),
+ ApplicationSort.Favorite => CreateComparer(IsAscending, app => new AppListFavoriteComparable(app)),
+ ApplicationSort.TitleId => CreateComparer(IsAscending, app => app.Id),
_ => null,
#pragma warning restore IDE0055
};
@@ -848,7 +890,8 @@ namespace Ryujinx.Ava.UI.ViewModels
CompareInfo compareInfo = CultureInfo.CurrentCulture.CompareInfo;
- return compareInfo.IndexOf(app.Name, _searchText, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0;
+ return compareInfo.IndexOf(app.Name, _searchText,
+ CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0;
}
return false;
@@ -862,21 +905,27 @@ namespace Ryujinx.Ava.UI.ViewModels
if (firmwareVersion == null)
{
- await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareNotFoundErrorMessage, filename));
+ await ContentDialogHelper.CreateErrorDialog(
+ LocaleManager.Instance.UpdateAndGetDynamicValue(
+ LocaleKeys.DialogFirmwareInstallerFirmwareNotFoundErrorMessage, filename));
return;
}
- string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallTitle, firmwareVersion.VersionString);
- string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallMessage, firmwareVersion.VersionString);
+ string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(
+ LocaleKeys.DialogFirmwareInstallerFirmwareInstallTitle, firmwareVersion.VersionString);
+ string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(
+ LocaleKeys.DialogFirmwareInstallerFirmwareInstallMessage, firmwareVersion.VersionString);
SystemVersion currentVersion = ContentManager.GetCurrentFirmwareVersion();
if (currentVersion != null)
{
- dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallSubMessage, currentVersion.VersionString);
+ dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(
+ LocaleKeys.DialogFirmwareInstallerFirmwareInstallSubMessage, currentVersion.VersionString);
}
- dialogMessage += LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallConfirmMessage];
+ dialogMessage +=
+ LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallConfirmMessage];
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
dialogTitle,
@@ -885,7 +934,8 @@ namespace Ryujinx.Ava.UI.ViewModels
LocaleManager.Instance[LocaleKeys.InputDialogNo],
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
- UpdateWaitWindow waitingDialog = new(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallWaitMessage]);
+ UpdateWaitWindow waitingDialog = new(dialogTitle,
+ LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallWaitMessage]);
if (result == UserResult.Yes)
{
@@ -906,7 +956,9 @@ namespace Ryujinx.Ava.UI.ViewModels
{
waitingDialog.Close();
- string message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallSuccessMessage, firmwareVersion.VersionString);
+ string message = LocaleManager.Instance.UpdateAndGetDynamicValue(
+ LocaleKeys.DialogFirmwareInstallerFirmwareInstallSuccessMessage,
+ firmwareVersion.VersionString);
await ContentDialogHelper.CreateInfoDialog(
dialogTitle,
@@ -919,7 +971,8 @@ namespace Ryujinx.Ava.UI.ViewModels
// Purge Applet Cache.
- DirectoryInfo miiEditorCacheFolder = new(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
+ DirectoryInfo miiEditorCacheFolder = new(Path.Combine(AppDataManager.GamesDirPath,
+ "0100000000001009", "cache"));
if (miiEditorCacheFolder.Exists)
{
@@ -940,10 +993,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
RefreshFirmwareStatus();
}
- })
- {
- Name = "GUI.FirmwareInstallerThread",
- };
+ }) { Name = "GUI.FirmwareInstallerThread", };
thread.Start();
}
@@ -968,17 +1018,22 @@ namespace Ryujinx.Ava.UI.ViewModels
try
{
string systemDirectory = AppDataManager.KeysDirPath;
- if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && Directory.Exists(AppDataManager.KeysDirPathUser))
+ if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile &&
+ Directory.Exists(AppDataManager.KeysDirPathUser))
{
systemDirectory = AppDataManager.KeysDirPathUser;
}
- string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallTitle);
- string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallMessage);
-
+ string dialogTitle =
+ LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallTitle);
+ string dialogMessage =
+ LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallMessage);
+
if (ContentManager.AreKeysAlredyPresent(systemDirectory))
{
- dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallSubMessage);
+ dialogMessage +=
+ LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys
+ .DialogKeysInstallerKeysInstallSubMessage);
}
dialogMessage += LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallConfirmMessage];
@@ -990,7 +1045,8 @@ namespace Ryujinx.Ava.UI.ViewModels
LocaleManager.Instance[LocaleKeys.InputDialogNo],
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
- UpdateWaitWindow waitingDialog = new(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallWaitMessage]);
+ UpdateWaitWindow waitingDialog = new(dialogTitle,
+ LocaleManager.Instance[LocaleKeys.DialogKeysInstallerKeysInstallWaitMessage]);
if (result == UserResult.Yes)
{
@@ -1011,7 +1067,9 @@ namespace Ryujinx.Ava.UI.ViewModels
{
waitingDialog.Close();
- string message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysInstallSuccessMessage);
+ string message =
+ LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys
+ .DialogKeysInstallerKeysInstallSuccessMessage);
await ContentDialogHelper.CreateInfoDialog(
dialogTitle,
@@ -1032,7 +1090,8 @@ namespace Ryujinx.Ava.UI.ViewModels
string message = ex.Message;
if (ex is FormatException)
{
- message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogKeysInstallerKeysNotFoundErrorMessage, filename);
+ message = LocaleManager.Instance.UpdateAndGetDynamicValue(
+ LocaleKeys.DialogKeysInstallerKeysNotFoundErrorMessage, filename);
}
await ContentDialogHelper.CreateErrorDialog(message);
@@ -1042,10 +1101,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
VirtualFileSystem.ReloadKeySet();
}
- })
- {
- Name = "GUI.KeysInstallerThread",
- };
+ }) { Name = "GUI.KeysInstallerThread", };
thread.Start();
}
@@ -1064,6 +1120,7 @@ namespace Ryujinx.Ava.UI.ViewModels
await ContentDialogHelper.CreateErrorDialog(ex.Message);
}
}
+
private void ProgressHandler(T state, int current, int total) where T : Enum
{
Dispatcher.UIThread.Post(() =>
@@ -1083,7 +1140,8 @@ namespace Ryujinx.Ava.UI.ViewModels
IsLoadingIndeterminate = false;
break;
case LoadState.Loaded:
- LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, _currentApplicationData.Name);
+ LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading,
+ _currentApplicationData.Name);
IsLoadingIndeterminate = true;
CacheLoadStatus = string.Empty;
break;
@@ -1104,7 +1162,8 @@ namespace Ryujinx.Ava.UI.ViewModels
IsLoadingIndeterminate = false;
break;
case ShaderCacheLoadingState.Loaded:
- LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, _currentApplicationData.Name);
+ LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading,
+ _currentApplicationData.Name);
IsLoadingIndeterminate = true;
CacheLoadStatus = string.Empty;
break;
@@ -1204,12 +1263,12 @@ namespace Ryujinx.Ava.UI.ViewModels
_rendererWaitEvent.Set();
}
- private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey, LoadContentFromFolderDelegate onDirsSelected, LocaleKeys dirSelectDialogTitle)
+ private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey,
+ LoadContentFromFolderDelegate onDirsSelected, LocaleKeys dirSelectDialogTitle)
{
- Optional> result = await StorageProvider.OpenMultiFolderPickerAsync(new FolderPickerOpenOptions
- {
- Title = LocaleManager.Instance[dirSelectDialogTitle]
- });
+ Optional> result =
+ await StorageProvider.OpenMultiFolderPickerAsync(
+ new FolderPickerOpenOptions { Title = LocaleManager.Instance[dirSelectDialogTitle] });
if (result.TryGet(out IReadOnlyList foldersToLoad))
{
@@ -1224,7 +1283,8 @@ namespace Ryujinx.Ava.UI.ViewModels
await Dispatcher.UIThread.InvokeAsync(async () =>
{
await ContentDialogHelper.ShowTextDialog(
- LocaleManager.Instance[numAdded > 0 || numRemoved > 0 ? LocaleKeys.RyujinxConfirm : LocaleKeys.RyujinxInfo],
+ LocaleManager.Instance[
+ numAdded > 0 || numRemoved > 0 ? LocaleKeys.RyujinxConfirm : LocaleKeys.RyujinxInfo],
msg,
string.Empty,
string.Empty,
@@ -1253,17 +1313,21 @@ namespace Ryujinx.Ava.UI.ViewModels
public void LoadConfigurableHotKeys()
{
- if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI, out Avalonia.Input.Key showUiKey))
+ if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI,
+ out Avalonia.Input.Key showUiKey))
{
ShowUiKey = new KeyGesture(showUiKey);
}
- if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out Avalonia.Input.Key screenshotKey))
+ if (AvaloniaKeyboardMappingHelper.TryGetAvaKey(
+ (Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot,
+ out Avalonia.Input.Key screenshotKey))
{
ScreenshotKey = new KeyGesture(screenshotKey);
}
- if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out Avalonia.Input.Key pauseKey))
+ if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause,
+ out Avalonia.Input.Key pauseKey))
{
PauseKey = new KeyGesture(pauseKey);
}
@@ -1283,7 +1347,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public void SetGridMode() => Glyph = Glyph.Grid;
- public void SetAspectRatio(AspectRatio aspectRatio) => ConfigurationState.Instance.Graphics.AspectRatio.Value = aspectRatio;
+ public void SetAspectRatio(AspectRatio aspectRatio) =>
+ ConfigurationState.Instance.Graphics.AspectRatio.Value = aspectRatio;
public async Task InstallFirmwareFromFile()
{
@@ -1375,7 +1440,8 @@ namespace Ryujinx.Ava.UI.ViewModels
}
catch (Exception ex)
{
- Logger.Error?.Print(LogClass.Application, $"Failed to create directory at path {screenshotsDir}. Error : {ex.GetType().Name}", "Screenshot");
+ Logger.Error?.Print(LogClass.Application,
+ $"Failed to create directory at path {screenshotsDir}. Error : {ex.GetType().Name}", "Screenshot");
return;
}
@@ -1448,7 +1514,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task ManageProfiles()
{
- await NavigationDialogHost.Show(AccountManager, ContentManager, VirtualFileSystem, LibHacHorizonManager.RyujinxClient);
+ await NavigationDialogHost.Show(AccountManager, ContentManager, VirtualFileSystem,
+ LibHacHorizonManager.RyujinxClient);
}
public void SimulateWakeUpMessage()
@@ -1525,7 +1592,8 @@ namespace Ryujinx.Ava.UI.ViewModels
}
else
{
- await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.MenuBarFileOpenFromFileError]);
+ await ContentDialogHelper.CreateErrorDialog(
+ LocaleManager.Instance[LocaleKeys.MenuBarFileOpenFromFileError]);
}
}
}
@@ -1550,17 +1618,17 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task OpenFolder()
{
- Optional result = await StorageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
- {
- Title = LocaleManager.Instance[LocaleKeys.LoadUnpackedGameFromFolderDialogTitle]
- });
+ Optional result = await StorageProvider.OpenSingleFolderPickerAsync(
+ new FolderPickerOpenOptions
+ {
+ Title = LocaleManager.Instance[LocaleKeys.LoadUnpackedGameFromFolderDialogTitle]
+ });
if (result.TryGet(out IStorageFolder value))
{
ApplicationData applicationData = new()
{
- Name = Path.GetFileNameWithoutExtension(value.Path.LocalPath),
- Path = value.Path.LocalPath,
+ Name = Path.GetFileNameWithoutExtension(value.Path.LocalPath), Path = value.Path.LocalPath,
};
await LoadApplication(applicationData);
@@ -1570,29 +1638,34 @@ namespace Ryujinx.Ava.UI.ViewModels
public static bool InitializeUserConfig(ApplicationData application)
{
// Code where conditions will be met before loading the user configuration (Global Config)
- string backendThreadingInit = Program.BackendThreadingArg ?? ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString();
+ string backendThreadingInit = Program.BackendThreadingArg ??
+ ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString();
// If a configuration is found in the "/games/xxxxxxxxxxxxxx" folder, the program will load the user setting.
string idGame = application.IdBaseString;
- if (ConfigurationFileFormat.TryLoad(Program.GetDirGameUserConfig(idGame), out ConfigurationFileFormat configurationFileFormat))
+ if (ConfigurationFileFormat.TryLoad(Program.GetDirGameUserConfig(idGame),
+ out ConfigurationFileFormat configurationFileFormat))
{
// Loads the user configuration, having previously changed the global configuration to the user configuration
- ConfigurationState.Instance.Load(configurationFileFormat, Program.GetDirGameUserConfig(idGame, true), idGame);
+ ConfigurationState.Instance.Load(configurationFileFormat, Program.GetDirGameUserConfig(idGame, true),
+ idGame);
- if (ConfigurationFileFormat.TryLoad(Program.GlobalConfigurationPath, out ConfigurationFileFormat configurationFileFormatExtra))
+ if (ConfigurationFileFormat.TryLoad(Program.GlobalConfigurationPath,
+ out ConfigurationFileFormat configurationFileFormatExtra))
{
//This is where the global configuration will be stored.
//This allows you to change the global configuration settings during the game (for example, the global input setting)
- ConfigurationState.InstanceExtra.Load(configurationFileFormatExtra, Program.GlobalConfigurationPath);
+ ConfigurationState.InstanceExtra.Load(configurationFileFormatExtra,
+ Program.GlobalConfigurationPath);
}
}
// Code where conditions will be executed after loading user configuration
if (ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString() != backendThreadingInit)
{
- Rebooter.RebootAppWithGame(application.Path,
+ Rebooter.RebootAppWithGame(application.Path,
[
- "--bt",
+ "--bt",
ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString()
]);
@@ -1602,7 +1675,8 @@ namespace Ryujinx.Ava.UI.ViewModels
return false;
}
- public async Task LoadApplication(ApplicationData application, bool startFullscreen = false, BlitStruct? customNacpData = null)
+ public async Task LoadApplication(ApplicationData application, bool startFullscreen = false,
+ BlitStruct? customNacpData = null)
{
if (InitializeUserConfig(application))
return;
@@ -1626,7 +1700,8 @@ namespace Ryujinx.Ava.UI.ViewModels
Logger.RestartTime();
- SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(application.Path, ConfigurationState.Instance.System.Language, application.Id);
+ SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(application.Path,
+ ConfigurationState.Instance.System.Language, application.Id);
PrepareLoadScreen();
@@ -1664,7 +1739,6 @@ namespace Ryujinx.Ava.UI.ViewModels
Thread gameThread = new(InitializeGame) { Name = "GUI.WindowThread" };
gameThread.Start();
-
}
public void SwitchToRenderer(bool startFullscreen) =>
@@ -1696,7 +1770,8 @@ namespace Ryujinx.Ava.UI.ViewModels
if (version != null)
{
- LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, version.VersionString);
+ LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion,
+ version.VersionString);
hasApplet = version.Major > 3;
}
@@ -1749,7 +1824,7 @@ namespace Ryujinx.Ava.UI.ViewModels
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId) && IsGameRunning)
{
string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
- AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId);
+ AmiiboWindow window = new(ShowAll, LastScannedAmiiboId ?? string.Empty, titleId);
await StyleableAppWindow.ShowAsync(window);
@@ -1762,22 +1837,24 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
}
+
public async Task OpenBinFile()
{
if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning)
{
- Optional result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions
- {
- Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
- FileTypeFilter = new List
+ Optional result = await StorageProvider.OpenSingleFilePickerAsync(
+ new FilePickerOpenOptions
{
- new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
+ Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
+ FileTypeFilter = new List
{
- Patterns = ["*.bin"],
+ new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
+ {
+ Patterns = ["*.bin"],
+ }
}
- }
- });
-
+ });
+
if (result.HasValue)
{
AppHost.Device.System.ScanAmiiboFromBin(result.Value.Path.LocalPath);
@@ -1828,9 +1905,11 @@ namespace Ryujinx.Ava.UI.ViewModels
if (ConfigurationState.Instance.Logger.EnableTrace.Value)
{
string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledMessage];
- string secondaryMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledConfirmMessage];
+ string secondaryMessage =
+ LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledConfirmMessage];
- UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(mainMessage, secondaryMessage);
+ UserResult result =
+ await ContentDialogHelper.CreateLocalizedConfirmationDialog(mainMessage, secondaryMessage);
if (result == UserResult.Yes)
{
@@ -1843,9 +1922,11 @@ namespace Ryujinx.Ava.UI.ViewModels
if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
{
string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledMessage];
- string secondaryMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledConfirmMessage];
+ string secondaryMessage =
+ LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledConfirmMessage];
- UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(mainMessage, secondaryMessage);
+ UserResult result =
+ await ContentDialogHelper.CreateLocalizedConfirmationDialog(mainMessage, secondaryMessage);
if (result == UserResult.Yes)
{
@@ -1900,7 +1981,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void ProcessTrimResult(String filename, XCIFileTrimmer.OperationOutcome operationOutcome)
{
- string notifyUser = operationOutcome.ToLocalisedText();
+ string notifyUser = operationOutcome.LocalizedText;
if (notifyUser != null)
{
@@ -1934,7 +2015,8 @@ namespace Ryujinx.Ava.UI.ViewModels
double savings = (double)trimmer.DiskSpaceSavingsB / 1024.0 / 1024.0;
double currentFileSize = (double)trimmer.FileSizeB / 1024.0 / 1024.0;
double cartDataSize = (double)trimmer.DataSizeB / 1024.0 / 1024.0;
- string secondaryText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TrimXCIFileDialogSecondaryText, currentFileSize, cartDataSize, savings);
+ string secondaryText = LocaleManager.Instance.UpdateAndGetDynamicValue(
+ LocaleKeys.TrimXCIFileDialogSecondaryText, currentFileSize, cartDataSize, savings);
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.TrimXCIFileDialogPrimaryText],
@@ -1950,7 +2032,9 @@ namespace Ryujinx.Ava.UI.ViewModels
{
Dispatcher.UIThread.Post(() =>
{
- StatusBarProgressStatusText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarXCIFileTrimming, Path.GetFileName(filename));
+ StatusBarProgressStatusText =
+ LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarXCIFileTrimming,
+ Path.GetFileName(filename));
StatusBarProgressStatusVisible = true;
StatusBarProgressMaximum = 1;
StatusBarProgressValue = 0;
@@ -1975,11 +2059,7 @@ namespace Ryujinx.Ava.UI.ViewModels
StatusBarVisible = false;
});
}
- })
- {
- Name = "GUI.XCIFileTrimmerThread",
- IsBackground = true,
- };
+ }) { Name = "GUI.XCIFileTrimmerThread", IsBackground = true, };
XCIFileTrimThread.Start();
}
}
@@ -2041,7 +2121,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public static RelayCommand OpenUserSaveDirectory { get; } =
Commands.CreateConditional(vm => vm?.SelectedApplication != null,
viewModel =>
- OpenSaveDirectory(viewModel, SaveDataType.Account, viewModel.AccountManager.LastOpenedUser.UserId.ToLibHac())
+ OpenSaveDirectory(viewModel, SaveDataType.Account,
+ viewModel.AccountManager.LastOpenedUser.UserId.ToLibHac())
);
public static RelayCommand OpenDeviceSaveDirectory { get; } =
@@ -2097,7 +2178,8 @@ namespace Ryujinx.Ava.UI.ViewModels
viewModel =>
{
string modsBasePath = ModLoader.GetModsBasePath();
- string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
+ string titleModsPath =
+ ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
OpenHelper.OpenFolder(titleModsPath);
});
@@ -2107,7 +2189,8 @@ namespace Ryujinx.Ava.UI.ViewModels
viewModel =>
{
string sdModsBasePath = ModLoader.GetSdModsBasePath();
- string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
+ string titleModsPath =
+ ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
OpenHelper.OpenFolder(titleModsPath);
});
diff --git a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs
index abfe5a4c5..45e67add0 100644
--- a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs
@@ -24,9 +24,11 @@ namespace Ryujinx.Ava.UI.ViewModels
{
private readonly string _modJsonPath;
- private AvaloniaList _mods = [];
- [ObservableProperty] private AvaloniaList _views = [];
- [ObservableProperty] private AvaloniaList _selectedMods = [];
+ [ObservableProperty]
+ public partial AvaloniaList Views { get; set; } = [];
+
+ [ObservableProperty]
+ public partial AvaloniaList SelectedMods { get; set; } = [];
private string _search;
private readonly ulong _applicationId;
@@ -37,15 +39,15 @@ namespace Ryujinx.Ava.UI.ViewModels
public AvaloniaList Mods
{
- get => _mods;
+ get;
set
{
- _mods = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ModCount));
Sort();
}
- }
+ } = [];
public string Search
{
@@ -58,10 +60,7 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
- public string ModCount
- {
- get => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count);
- }
+ public string ModCount => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count);
public ModManagerViewModel(ulong applicationId, ulong applicationIdBase, ApplicationLibrary appLibrary)
{
diff --git a/src/Ryujinx/UI/ViewModels/ProfileSelectorDialogViewModel.cs b/src/Ryujinx/UI/ViewModels/ProfileSelectorDialogViewModel.cs
index 979e1616a..0aa326b55 100644
--- a/src/Ryujinx/UI/ViewModels/ProfileSelectorDialogViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/ProfileSelectorDialogViewModel.cs
@@ -7,8 +7,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public partial class ProfileSelectorDialogViewModel : BaseModel
{
- [ObservableProperty] private UserId _selectedUserId;
+ [ObservableProperty]
+ public partial UserId SelectedUserId { get; set; }
- [ObservableProperty] private ObservableCollection _profiles = [];
+ [ObservableProperty]
+ public partial ObservableCollection Profiles { get; set; } = [];
}
}
diff --git a/src/Ryujinx/UI/ViewModels/SettingsHacksViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsHacksViewModel.cs
index 230887e34..65e91f41f 100644
--- a/src/Ryujinx/UI/ViewModels/SettingsHacksViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/SettingsHacksViewModel.cs
@@ -15,9 +15,13 @@ namespace Ryujinx.Ava.UI.ViewModels
_baseViewModel = settingsVm;
}
- [ObservableProperty] private bool _xc2MenuSoftlockFix = ConfigurationState.Instance.Hacks.Xc2MenuSoftlockFix;
- [ObservableProperty] private bool _nifmDisableIsAnyInternetRequestAccepted = ConfigurationState.Instance.Hacks.DisableNifmIsAnyInternetRequestAccepted;
+ [ObservableProperty]
+ public partial bool Xc2MenuSoftlockFix { get; set; } = ConfigurationState.Instance.Hacks.Xc2MenuSoftlockFix;
+ [ObservableProperty]
+ public partial bool NifmDisableIsAnyInternetRequestAccepted { get; set; } = ConfigurationState.Instance.Hacks.DisableNifmIsAnyInternetRequestAccepted;
+
+
public static string Xc2MenuFixTooltip { get; } = Lambda.String(sb =>
{
sb.AppendLine(
diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
index c590e0cb0..894f06969 100644
--- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
@@ -19,7 +19,6 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Helper;
-using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE;
@@ -46,47 +45,49 @@ namespace Ryujinx.Ava.UI.ViewModels
private readonly Dictionary _networkInterfaces;
- private float _customResolutionScale;
private int _resolutionScale;
- private int _graphicsBackendMultithreadingIndex;
- private float _volume;
- [ObservableProperty] private bool _isVulkanAvailable = true;
- [ObservableProperty] private bool _gameListNeedsRefresh;
+ [ObservableProperty]
+ public partial bool IsVulkanAvailable { get; set; } = true;
+
+ [ObservableProperty]
+ public partial bool GameListNeedsRefresh { get; set; }
+
private readonly List _gpuIds = [];
- public bool _useInputGlobalConfig;
- private int _graphicsBackendIndex;
private int _scalingFilter;
- private int _scalingFilterLevel;
private int _customVSyncInterval;
- private bool _enableCustomVSyncInterval;
private int _customVSyncIntervalPercentageProxy;
private VSyncMode _vSyncMode;
- private long _turboModeMultiplier;
public event Action CloseWindow;
public event Action SaveSettingsEvent;
public event Action LocalGlobalInputSwitchEvent;
- private int _networkInterfaceIndex;
- private int _multiplayerModeIndex;
- private string _ldnPassphrase;
- [ObservableProperty] private string _ldnServer;
-
- private bool _enableGDBStub;
- private ushort _gdbStubPort;
- private bool _debuggerSuspendOnStart;
-
public SettingsHacksViewModel DirtyHacks { get; }
- private readonly bool _isGameRunning;
- private readonly Bitmap _gameIcon;
- private readonly string _gameTitle;
- private readonly string _gamePath;
- private readonly string _gameId;
- public bool IsGameRunning => _isGameRunning;
- public Bitmap GameIcon => _gameIcon;
- public string GamePath => _gamePath;
- public string GameTitle => _gameTitle;
- public string GameId => _gameId;
+ public bool IsGameRunning
+ {
+ get;
+ }
+
+ public Bitmap GameIcon
+ {
+ get;
+ }
+
+ public string GamePath
+ {
+ get;
+ }
+
+ public string GameTitle
+ {
+ get;
+ }
+
+ public string GameId
+ {
+ get;
+ }
+
public bool IsGameTitleNotNull => !string.IsNullOrEmpty(GameTitle);
public double PanelOpacity => IsGameTitleNotNull ? 0.5 : 1;
@@ -104,17 +105,18 @@ namespace Ryujinx.Ava.UI.ViewModels
public int GraphicsBackendMultithreadingIndex
{
- get => _graphicsBackendMultithreadingIndex;
+ get;
set
{
- _graphicsBackendMultithreadingIndex = value;
+ field = value;
- if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value)
+ if (field != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value)
{
Dispatcher.UIThread.InvokeAsync(() =>
- ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
- string.Empty,
- string.Empty,
+ ContentDialogHelper.CreateInfoDialog(
+ LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
+ string.Empty,
+ string.Empty,
LocaleManager.Instance[LocaleKeys.InputDialogOk],
LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle])
);
@@ -126,10 +128,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public float CustomResolutionScale
{
- get => _customResolutionScale;
+ get;
set
{
- _customResolutionScale = MathF.Round(value, 1);
+ field = MathF.Round(value, 1);
OnPropertyChanged();
}
@@ -152,12 +154,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public int FocusLostActionType { get; set; }
public bool UseGlobalInputConfig
- {
- get => _useInputGlobalConfig;
+ {
+ get;
set
{
- _useInputGlobalConfig = value;
- LocalGlobalInputSwitchEvent?.Invoke(_useInputGlobalConfig);
+ field = value;
+ LocalGlobalInputSwitchEvent?.Invoke(field);
OnPropertyChanged(nameof(InputPanelOpacity));
OnPropertyChanged();
}
@@ -196,10 +198,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableCustomVSyncInterval
{
- get => _enableCustomVSyncInterval;
+ get;
set
{
- _enableCustomVSyncInterval = value;
+ field = value;
if (_vSyncMode == VSyncMode.Custom && !value)
{
VSyncMode = VSyncMode.Switch;
@@ -233,12 +235,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public long TurboMultiplier
{
- get => _turboModeMultiplier;
+ get;
set
{
- if (_turboModeMultiplier != value)
+ if (field != value)
{
- _turboModeMultiplier = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged((nameof(TurboMultiplierPercentageText)));
@@ -285,10 +287,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public string LdnPassphrase
{
- get => _ldnPassphrase;
+ get;
set
{
- _ldnPassphrase = value;
+ field = value;
IsInvalidLdnPassphraseVisible = !ValidateLdnPassphrase(value);
OnPropertyChanged();
@@ -304,29 +306,33 @@ namespace Ryujinx.Ava.UI.ViewModels
public int AspectRatio { get; set; }
public int AntiAliasingEffect { get; set; }
public string ScalingFilterLevelText => ScalingFilterLevel.ToString("0");
+
public int ScalingFilterLevel
{
- get => _scalingFilterLevel;
+ get;
set
{
- _scalingFilterLevel = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ScalingFilterLevelText));
}
}
+
public int OpenglDebugLevel { get; set; }
public int MemoryMode { get; set; }
public int BaseStyleIndex { get; set; }
+
public int GraphicsBackendIndex
{
- get => _graphicsBackendIndex;
+ get;
set
{
- _graphicsBackendIndex = value;
+ field = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsVulkanSelected));
}
}
+
public int ScalingFilter
{
get => _scalingFilter;
@@ -342,12 +348,12 @@ namespace Ryujinx.Ava.UI.ViewModels
public float Volume
{
- get => _volume;
+ get;
set
{
- _volume = value;
+ field = value;
- ConfigurationState.Instance.System.AudioVolume.Value = _volume / 100;
+ ConfigurationState.Instance.System.AudioVolume.Value = field / 100;
OnPropertyChanged();
}
@@ -373,19 +379,19 @@ namespace Ryujinx.Ava.UI.ViewModels
public int NetworkInterfaceIndex
{
- get => _networkInterfaceIndex;
+ get;
set
{
- _networkInterfaceIndex = value != -1 ? value : 0;
+ field = value != -1 ? value : 0;
}
}
public int MultiplayerModeIndex
{
- get => _multiplayerModeIndex;
+ get;
set
{
- _multiplayerModeIndex = value;
+ field = value;
}
}
@@ -393,31 +399,31 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableGdbStub
{
- get => _enableGDBStub;
+ get;
set
{
- _enableGDBStub = value;
- ConfigurationState.Instance.Debug.EnableGdbStub.Value = _enableGDBStub;
+ field = value;
+ ConfigurationState.Instance.Debug.EnableGdbStub.Value = field;
}
}
public ushort GDBStubPort
{
- get => _gdbStubPort;
+ get;
set
{
- _gdbStubPort = value;
- ConfigurationState.Instance.Debug.GdbStubPort.Value = _gdbStubPort;
+ field = value;
+ ConfigurationState.Instance.Debug.GdbStubPort.Value = field;
}
}
public bool DebuggerSuspendOnStart
{
- get => _debuggerSuspendOnStart;
+ get;
set
{
- _debuggerSuspendOnStart = value;
- ConfigurationState.Instance.Debug.DebuggerSuspendOnStart.Value = _debuggerSuspendOnStart;
+ field = value;
+ ConfigurationState.Instance.Debug.DebuggerSuspendOnStart.Value = field;
}
}
@@ -450,13 +456,13 @@ namespace Ryujinx.Ava.UI.ViewModels
if (gameIconData is { Length: > 0 })
{
using MemoryStream ms = new(gameIconData);
- _gameIcon = new Bitmap(ms);
+ GameIcon = new Bitmap(ms);
}
- _isGameRunning = gameRunning;
- _gamePath = gamePath;
- _gameTitle = gameName;
- _gameId = gameId;
+ IsGameRunning = gameRunning;
+ GamePath = gamePath;
+ GameTitle = gameName;
+ GameId = gameId;
if (customConfig) // During the game. If there is no user config, then load the global config window
{
@@ -717,7 +723,6 @@ namespace Ryujinx.Ava.UI.ViewModels
MultiplayerModeIndex = (int)config.Multiplayer.Mode.Value;
DisableP2P = config.Multiplayer.DisableP2p;
LdnPassphrase = config.Multiplayer.LdnPassphrase;
- LdnServer = config.Multiplayer.LdnServer;
// Debug
EnableGdbStub = config.Debug.EnableGdbStub.Value;
@@ -842,7 +847,6 @@ namespace Ryujinx.Ava.UI.ViewModels
config.Multiplayer.Mode.Value = (MultiplayerMode)MultiplayerModeIndex;
config.Multiplayer.DisableP2p.Value = DisableP2P;
config.Multiplayer.LdnPassphrase.Value = LdnPassphrase;
- config.Multiplayer.LdnServer.Value = LdnServer;
// Debug
config.Debug.EnableGdbStub.Value = EnableGdbStub;
diff --git a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs
index 74876774e..3d34643ab 100644
--- a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs
@@ -21,10 +21,17 @@ namespace Ryujinx.Ava.UI.ViewModels
private ApplicationLibrary ApplicationLibrary { get; }
private ApplicationData ApplicationData { get; }
- [ObservableProperty] private AvaloniaList _titleUpdates = [];
- [ObservableProperty] private AvaloniaList