Compare commits

...

4 Commits

Author SHA1 Message Date
gdkchan
dbe43c1719 Fix SSL GetCertificates with certificate ID set to All (#3727)
* Fix SSL GetCertificates with certificate ID set to All

* Fix last entry status value
2022-09-29 12:45:25 -03:00
riperiperi
f502cfaf62 Vulkan: Zero blend state when disabled or write mask is 0 (#3719)
* Zero blend state when disabled or write mask is 0

Any difference in the blend state when blend is disabled is meaningless, but Ryujinx would compare different disabled blends and compile them as separate pipelines. This change ensures that all pipelines where blend state is meaningless record it as such, which avoids compiling a bunch of pipelines that are essentially identical.

The NVIDIA driver is pretty forgiving when it comes to silly pipeline misses like this, but other drivers don't offer the same level of kindness.

This should reduce stuttering on those drivers, and might improve overall performance very slightly due to less pipeline variants being in the hash table.

* Fix blend possibly being wrong when an attachment is unmasked
2022-09-29 12:32:49 -03:00
gdkchan
1fd5cf2b4a Fix ListOpenContextStoredUsers and stub LoadOpenContext (#3718)
* Fix ListOpenContextStoredUsers and stub LoadOpenContext

* Remove nonsensical comment
2022-09-27 21:24:52 -03:00
LDj3SNuD
814f75142e Fpsr and Fpcr freed. (#3701)
* Implemented in IR the managed methods of the Saturating region ...

... of the SoftFallback class (the SatQ ones).

The need to natively manage the Fpcr and Fpsr system registers is still a fact.

Contributes to https://github.com/Ryujinx/Ryujinx/issues/2917 ; I will open another PR to implement in Intrinsics-branchless the methods of the Saturation region as well (the SatXXXToXXX ones).

All instructions involved have been tested locally in both release and debug modes, in both lowcq and highcq.

* Ptc.InternalVersion = 3665

* Addressed PR feedback.

* Implemented in IR the managed methods of the ShlReg region of the SoftFallback class.

It also includes the last two SatQ ones (following up on https://github.com/Ryujinx/Ryujinx/pull/3665).

All instructions involved have been tested locally in both release and debug modes, in both lowcq and highcq.

* Fpsr and Fpcr freed.

Handling/isolation of Fpsr and Fpcr via register for IR and via memory for Tests and Threads, with synchronization to context exchanges (explicit for SoftFloat); without having to call managed methods. Thanks to the inlining work of the previous two PRs and others in this.

Tests performed locally in both release and debug modes, in both lowcq and highcq, with FastFP to true and false (explicit FP tests included). Tested with the title Tony Hawk's PS.

Depends on shlreg.

* Update InstEmitSimdHelper.cs

* De-magic Masks.

Remove the Stride and Len flags; Fpsr.NZCV are A32 only, then moved to Fpscr: this leads to emitting less IR in reference to Get/Set Fpsr/Fpcr/Fpscr methods in reference to Mrs/Msr (A64) and Vmrs/Vmsr (A32) instructions.

* Addressed PR feedback.
2022-09-20 18:55:13 -03:00
29 changed files with 454 additions and 433 deletions

View File

@@ -726,7 +726,7 @@ namespace ARMeilleure.Instructions
{ {
EmitVectorAcrossVectorOpF(context, (op1, op2) => EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{ {
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)), op1, op2); return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2);
}); });
} }
} }
@@ -774,7 +774,7 @@ namespace ARMeilleure.Instructions
{ {
EmitVectorAcrossVectorOpF(context, (op1, op2) => EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{ {
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)), op1, op2); return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2);
}); });
} }
} }
@@ -900,7 +900,7 @@ namespace ARMeilleure.Instructions
{ {
EmitVectorAcrossVectorOpF(context, (op1, op2) => EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{ {
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)), op1, op2); return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2);
}); });
} }
} }
@@ -948,7 +948,7 @@ namespace ARMeilleure.Instructions
{ {
EmitVectorAcrossVectorOpF(context, (op1, op2) => EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{ {
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)), op1, op2); return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2);
}); });
} }
} }
@@ -1633,37 +1633,17 @@ namespace ARMeilleure.Instructions
public static void Frinti_S(ArmEmitterContext context) public static void Frinti_S(ArmEmitterContext context)
{ {
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
EmitScalarUnaryOpF(context, (op1) => EmitScalarUnaryOpF(context, (op1) =>
{ {
if (op.Size == 0) return EmitRoundByRMode(context, op1);
{
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
}
else /* if (op.Size == 1) */
{
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
}
}); });
} }
public static void Frinti_V(ArmEmitterContext context) public static void Frinti_V(ArmEmitterContext context)
{ {
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
int sizeF = op.Size & 1;
EmitVectorUnaryOpF(context, (op1) => EmitVectorUnaryOpF(context, (op1) =>
{ {
if (sizeF == 0) return EmitRoundByRMode(context, op1);
{
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
}
else /* if (sizeF == 1) */
{
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
}
}); });
} }
@@ -1759,37 +1739,17 @@ namespace ARMeilleure.Instructions
public static void Frintx_S(ArmEmitterContext context) public static void Frintx_S(ArmEmitterContext context)
{ {
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
EmitScalarUnaryOpF(context, (op1) => EmitScalarUnaryOpF(context, (op1) =>
{ {
if (op.Size == 0) return EmitRoundByRMode(context, op1);
{
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
}
else /* if (op.Size == 1) */
{
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
}
}); });
} }
public static void Frintx_V(ArmEmitterContext context) public static void Frintx_V(ArmEmitterContext context)
{ {
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
int sizeF = op.Size & 1;
EmitVectorUnaryOpF(context, (op1) => EmitVectorUnaryOpF(context, (op1) =>
{ {
if (sizeF == 0) return EmitRoundByRMode(context, op1);
{
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
}
else /* if (sizeF == 1) */
{
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
}
}); });
} }

View File

@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State; using ARMeilleure.State;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using System; using System;
using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper; using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper; using static ARMeilleure.Instructions.InstEmitSimdHelper;
@@ -178,37 +177,20 @@ namespace ARMeilleure.Instructions
private static void EmitCmpOpF32(ArmEmitterContext context, string name, bool zero) private static void EmitCmpOpF32(ArmEmitterContext context, string name, bool zero)
{ {
Operand one = Const(1);
if (zero) if (zero)
{ {
EmitVectorUnaryOpF32(context, (m) => EmitVectorUnaryOpF32(context, (m) =>
{ {
OperandType type = m.Type; Operand zeroOp = m.Type == OperandType.FP64 ? ConstF(0.0d) : ConstF(0.0f);
if (type == OperandType.FP64) return EmitSoftFloatCallDefaultFpscr(context, name, m, zeroOp);
{
return context.Call(typeof(SoftFloat64).GetMethod(name), m, ConstF(0.0d), one);
}
else
{
return context.Call(typeof(SoftFloat32).GetMethod(name), m, ConstF(0.0f), one);
}
}); });
} }
else else
{ {
EmitVectorBinaryOpF32(context, (n, m) => EmitVectorBinaryOpF32(context, (n, m) =>
{ {
OperandType type = n.Type; return EmitSoftFloatCallDefaultFpscr(context, name, n, m);
if (type == OperandType.FP64)
{
return context.Call(typeof(SoftFloat64).GetMethod(name), n, m, one);
}
else
{
return context.Call(typeof(SoftFloat32).GetMethod(name), n, m, one);
}
}); });
} }
} }
@@ -357,11 +339,7 @@ namespace ARMeilleure.Instructions
me = ExtractScalar(context, type, op.Vm); me = ExtractScalar(context, type, op.Vm);
} }
MethodInfo info = sizeF != 0 Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs));
? typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare))
: typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare));
Operand nzcv = context.Call(info, ne, me, Const(signalNaNs));
EmitSetFpscrNzcv(context, nzcv); EmitSetFpscrNzcv(context, nzcv);
} }

View File

@@ -76,7 +76,9 @@ namespace ARMeilleure.Instructions
{ {
Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0); Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0);
context.StoreToContext();
Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne); Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
context.LoadFromContext();
res = context.ZeroExtend16(OperandType.I64, res); res = context.ZeroExtend16(OperandType.I64, res);
@@ -98,7 +100,9 @@ namespace ARMeilleure.Instructions
{ {
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1); Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
context.StoreToContext();
Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne); Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
context.LoadFromContext();
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
} }
@@ -120,7 +124,9 @@ namespace ARMeilleure.Instructions
{ {
Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0); Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0);
context.StoreToContext();
Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne); Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne);
context.LoadFromContext();
res = context.ZeroExtend16(OperandType.I64, res); res = context.ZeroExtend16(OperandType.I64, res);
@@ -143,7 +149,9 @@ namespace ARMeilleure.Instructions
{ {
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1); Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
context.StoreToContext();
Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne); Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne);
context.LoadFromContext();
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
} }
@@ -224,7 +232,9 @@ namespace ARMeilleure.Instructions
{ {
Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1); Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1);
context.StoreToContext();
Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne); Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
context.LoadFromContext();
res = context.VectorInsert(res, e, index); res = context.VectorInsert(res, e, index);
} }
@@ -333,7 +343,9 @@ namespace ARMeilleure.Instructions
if (sizeF == 0) if (sizeF == 0)
{ {
context.StoreToContext();
Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne); Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
context.LoadFromContext();
e = context.ZeroExtend16(OperandType.I64, e); e = context.ZeroExtend16(OperandType.I64, e);

View File

@@ -161,34 +161,15 @@ namespace ARMeilleure.Instructions
{ {
Operand toConvert = ExtractScalar(context, floatSize, op.Vm); Operand toConvert = ExtractScalar(context, floatSize, op.Vm);
Operand asInteger;
// TODO: Fast Path. // TODO: Fast Path.
if (roundWithFpscr) if (roundWithFpscr)
{ {
MethodInfo info; toConvert = EmitRoundByRMode(context, toConvert);
if (floatSize == OperandType.FP64)
{
info = unsigned
? typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))
: typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32));
}
else
{
info = unsigned
? typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))
: typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32));
}
asInteger = context.Call(info, toConvert);
}
else
{
// Round towards zero.
asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
} }
// Round towards zero.
Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
InsertScalar(context, op.Vd, asInteger); InsertScalar(context, op.Vd, asInteger);
} }
} }
@@ -271,9 +252,7 @@ namespace ARMeilleure.Instructions
break; break;
} }
Operand asInteger; Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
InsertScalar(context, op.Vd, asInteger); InsertScalar(context, op.Vd, asInteger);
} }
@@ -399,15 +378,9 @@ namespace ARMeilleure.Instructions
// VRINTX (floating-point). // VRINTX (floating-point).
public static void Vrintx_S(ArmEmitterContext context) public static void Vrintx_S(ArmEmitterContext context)
{ {
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
bool doubleSize = (op.Size & 1) == 1;
string methodName = doubleSize ? nameof(SoftFallback.Round) : nameof(SoftFallback.RoundF);
EmitScalarUnaryOpF32(context, (op1) => EmitScalarUnaryOpF32(context, (op1) =>
{ {
MethodInfo info = typeof(SoftFallback).GetMethod(methodName); return EmitRoundByRMode(context, op1);
return context.Call(info, op1);
}); });
} }

View File

@@ -361,6 +361,54 @@ namespace ARMeilleure.Instructions
return context.Call(info, n, Const((int)roundMode)); return context.Call(info, n, Const((int)roundMode));
} }
public static Operand EmitGetRoundingMode(ArmEmitterContext context)
{
Operand rMode = context.ShiftLeft(GetFpFlag(FPState.RMode1Flag), Const(1));
rMode = context.BitwiseOr(rMode, GetFpFlag(FPState.RMode0Flag));
return rMode;
}
public static Operand EmitRoundByRMode(ArmEmitterContext context, Operand op)
{
Debug.Assert(op.Type == OperandType.FP32 || op.Type == OperandType.FP64);
Operand lbl1 = Label();
Operand lbl2 = Label();
Operand lbl3 = Label();
Operand lblEnd = Label();
Operand rN = Const((int)FPRoundingMode.ToNearest);
Operand rP = Const((int)FPRoundingMode.TowardsPlusInfinity);
Operand rM = Const((int)FPRoundingMode.TowardsMinusInfinity);
Operand res = context.AllocateLocal(op.Type);
Operand rMode = EmitGetRoundingMode(context);
context.BranchIf(lbl1, rMode, rN, Comparison.NotEqual);
context.Copy(res, EmitRoundMathCall(context, MidpointRounding.ToEven, op));
context.Branch(lblEnd);
context.MarkLabel(lbl1);
context.BranchIf(lbl2, rMode, rP, Comparison.NotEqual);
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Ceiling), op));
context.Branch(lblEnd);
context.MarkLabel(lbl2);
context.BranchIf(lbl3, rMode, rM, Comparison.NotEqual);
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Floor), op));
context.Branch(lblEnd);
context.MarkLabel(lbl3);
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Truncate), op));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);
return res;
}
public static Operand EmitSoftFloatCall(ArmEmitterContext context, string name, params Operand[] callArgs) public static Operand EmitSoftFloatCall(ArmEmitterContext context, string name, params Operand[] callArgs)
{ {
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp; IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
@@ -369,7 +417,11 @@ namespace ARMeilleure.Instructions
? typeof(SoftFloat32).GetMethod(name) ? typeof(SoftFloat32).GetMethod(name)
: typeof(SoftFloat64).GetMethod(name); : typeof(SoftFloat64).GetMethod(name);
return context.Call(info, callArgs); context.StoreToContext();
Operand res = context.Call(info, callArgs);
context.LoadFromContext();
return res;
} }
public static void EmitScalarBinaryOpByElemF(ArmEmitterContext context, Func2I emit) public static void EmitScalarBinaryOpByElemF(ArmEmitterContext context, Func2I emit)
@@ -1269,7 +1321,7 @@ namespace ARMeilleure.Instructions
public static void EmitSseOrAvxEnterFtzAndDazModesOpF(ArmEmitterContext context, out Operand isTrue) public static void EmitSseOrAvxEnterFtzAndDazModesOpF(ArmEmitterContext context, out Operand isTrue)
{ {
isTrue = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz))); isTrue = GetFpFlag(FPState.FzFlag);
Operand lblTrue = Label(); Operand lblTrue = Label();
context.BranchIfFalse(lblTrue, isTrue); context.BranchIfFalse(lblTrue, isTrue);
@@ -1281,9 +1333,7 @@ namespace ARMeilleure.Instructions
public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = default) public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = default)
{ {
isTrue = isTrue == default isTrue = isTrue == default ? GetFpFlag(FPState.FzFlag) : isTrue;
? context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)))
: isTrue;
Operand lblTrue = Label(); Operand lblTrue = Label();
context.BranchIfFalse(lblTrue, isTrue); context.BranchIfFalse(lblTrue, isTrue);
@@ -1552,13 +1602,13 @@ namespace ARMeilleure.Instructions
context.BranchIf(lbl1, op, zeroL, Comparison.LessOrEqual); context.BranchIf(lbl1, op, zeroL, Comparison.LessOrEqual);
context.Copy(res, maxT); context.Copy(res, maxT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lbl1); context.MarkLabel(lbl1);
context.BranchIf(lblEnd, op, zeroL, Comparison.GreaterOrEqual); context.BranchIf(lblEnd, op, zeroL, Comparison.GreaterOrEqual);
context.Copy(res, minT); context.Copy(res, minT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1583,7 +1633,7 @@ namespace ARMeilleure.Instructions
context.BranchIf(lblEnd, op, zeroUL, Comparison.LessOrEqualUI); context.BranchIf(lblEnd, op, zeroUL, Comparison.LessOrEqualUI);
context.Copy(res, maxT); context.Copy(res, maxT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1610,13 +1660,13 @@ namespace ARMeilleure.Instructions
context.BranchIf(lbl1, op, maxT, Comparison.LessOrEqual); context.BranchIf(lbl1, op, maxT, Comparison.LessOrEqual);
context.Copy(res, maxT); context.Copy(res, maxT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lbl1); context.MarkLabel(lbl1);
context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual); context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual);
context.Copy(res, minT); context.Copy(res, minT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1641,7 +1691,7 @@ namespace ARMeilleure.Instructions
context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI); context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI);
context.Copy(res, maxT); context.Copy(res, maxT);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1663,7 +1713,7 @@ namespace ARMeilleure.Instructions
context.BranchIf(lblEnd, op, minL, Comparison.NotEqual); context.BranchIf(lblEnd, op, minL, Comparison.NotEqual);
context.Copy(res, maxL); context.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1691,7 +1741,7 @@ namespace ARMeilleure.Instructions
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL); Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL)); context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1713,7 +1763,7 @@ namespace ARMeilleure.Instructions
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI); context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
context.Copy(res, maxUL); context.Copy(res, maxUL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1741,7 +1791,7 @@ namespace ARMeilleure.Instructions
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL); Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL)); context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1763,7 +1813,7 @@ namespace ARMeilleure.Instructions
context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI); context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI);
context.Copy(res, zeroL); context.Copy(res, zeroL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1790,19 +1840,19 @@ namespace ARMeilleure.Instructions
Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add); Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add);
context.BranchIf(lblEnd, notOp2AndRes, zeroL, Comparison.GreaterOrEqual); context.BranchIf(lblEnd, notOp2AndRes, zeroL, Comparison.GreaterOrEqual);
context.Copy(res, maxL); context.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lbl1); context.MarkLabel(lbl1);
context.BranchIf(lbl2, op2, zeroL, Comparison.Less); context.BranchIf(lbl2, op2, zeroL, Comparison.Less);
context.Copy(res, maxL); context.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lbl2); context.MarkLabel(lbl2);
context.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI); context.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI);
context.Copy(res, maxL); context.Copy(res, maxL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);
@@ -1828,14 +1878,14 @@ namespace ARMeilleure.Instructions
context.BranchIf(lbl1, op1, zeroL, Comparison.Less); context.BranchIf(lbl1, op1, zeroL, Comparison.Less);
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI); context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
context.Copy(res, maxUL); context.Copy(res, maxUL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lbl1); context.MarkLabel(lbl1);
context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI); context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI);
context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual); context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual);
context.Copy(res, zeroL); context.Copy(res, zeroL);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.Branch(lblEnd); context.Branch(lblEnd);
context.MarkLabel(lblEnd); context.MarkLabel(lblEnd);

View File

@@ -1181,7 +1181,11 @@ namespace ARMeilleure.Instructions
Array.Resize(ref callArgs, callArgs.Length + 1); Array.Resize(ref callArgs, callArgs.Length + 1);
callArgs[callArgs.Length - 1] = Const(1); callArgs[callArgs.Length - 1] = Const(1);
return context.Call(info, callArgs); context.StoreToContext();
Operand res = context.Call(info, callArgs);
context.LoadFromContext();
return res;
} }
public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size) public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size)

View File

@@ -1,5 +1,6 @@
using ARMeilleure.Decoders; using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
@@ -378,7 +379,7 @@ namespace ARMeilleure.Instructions
context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt)); context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt));
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetFpFlag(context, FPState.QcFlag, Const(1));
context.MarkLabel(lblNoSat); context.MarkLabel(lblNoSat);

View File

@@ -31,8 +31,8 @@ namespace ARMeilleure.Instructions
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break; case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break; case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return; case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break; case 0b11_011_0100_0100_000: EmitGetFpcr(context); return;
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break; case 0b11_011_0100_0100_001: EmitGetFpsr(context); return;
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break; case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break; case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break; case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
@@ -53,9 +53,9 @@ namespace ARMeilleure.Instructions
switch (GetPackedId(op)) switch (GetPackedId(op))
{ {
case 0b11_011_0100_0010_000: EmitSetNzcv(context); return; case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)); break; case 0b11_011_0100_0100_000: EmitSetFpcr(context); return;
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)); break; case 0b11_011_0100_0100_001: EmitSetFpsr(context); return;
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break; case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break;
default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
@@ -121,39 +121,91 @@ namespace ARMeilleure.Instructions
{ {
OpCodeSystem op = (OpCodeSystem)context.CurrOp; OpCodeSystem op = (OpCodeSystem)context.CurrOp;
Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); Operand nzcv = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)); nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)); nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)); nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); SetIntOrZR(context, op.Rt, nzcv);
}
SetIntOrZR(context, op.Rt, nzcvSh); private static void EmitGetFpcr(ArmEmitterContext context)
{
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
Operand fpcr = Const(0);
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
{
if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
{
fpcr = context.BitwiseOr(fpcr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
}
}
SetIntOrZR(context, op.Rt, fpcr);
}
private static void EmitGetFpsr(ArmEmitterContext context)
{
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
Operand fpsr = Const(0);
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
{
if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
{
fpsr = context.BitwiseOr(fpsr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
}
}
SetIntOrZR(context, op.Rt, fpsr);
} }
private static void EmitSetNzcv(ArmEmitterContext context) private static void EmitSetNzcv(ArmEmitterContext context)
{ {
OpCodeSystem op = (OpCodeSystem)context.CurrOp; OpCodeSystem op = (OpCodeSystem)context.CurrOp;
Operand t = GetIntOrZR(context, op.Rt); Operand nzcv = GetIntOrZR(context, op.Rt);
t = context.ConvertI64ToI32(t); nzcv = context.ConvertI64ToI32(nzcv);
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag)); SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.VFlag)), Const(1)));
v = context.BitwiseAnd (v, Const(1)); SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.CFlag)), Const(1)));
SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.ZFlag)), Const(1)));
SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.NFlag)), Const(1)));
}
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag)); private static void EmitSetFpcr(ArmEmitterContext context)
c = context.BitwiseAnd (c, Const(1)); {
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag)); Operand fpcr = GetIntOrZR(context, op.Rt);
z = context.BitwiseAnd (z, Const(1)); fpcr = context.ConvertI64ToI32(fpcr);
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag)); for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
n = context.BitwiseAnd (n, Const(1)); {
if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
{
SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpcr, Const(flag)), Const(1)));
}
}
}
SetFlag(context, PState.VFlag, v); private static void EmitSetFpsr(ArmEmitterContext context)
SetFlag(context, PState.CFlag, c); {
SetFlag(context, PState.ZFlag, z); OpCodeSystem op = (OpCodeSystem)context.CurrOp;
SetFlag(context, PState.NFlag, n);
Operand fpsr = GetIntOrZR(context, op.Rt);
fpsr = context.ConvertI64ToI32(fpsr);
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
{
if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
{
SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpsr, Const(flag)), Const(1)));
}
}
} }
} }
} }

View File

@@ -169,14 +169,11 @@ namespace ARMeilleure.Instructions
} }
else else
{ {
Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); Operand spsr = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)); spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)); spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)); spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
Operand qSh = context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag)); spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag)));
Operand spsr = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
spsr = context.BitwiseOr(spsr, qSh);
// TODO: Remaining flags. // TODO: Remaining flags.
@@ -200,8 +197,7 @@ namespace ARMeilleure.Instructions
EmitSetNzcv(context, value); EmitSetNzcv(context, value);
Operand q = context.ShiftRightUI(value, Const((int)PState.QFlag)); Operand q = context.BitwiseAnd(context.ShiftRightUI(value, Const((int)PState.QFlag)), Const(1));
q = context.BitwiseAnd(q, Const(1));
SetFlag(context, PState.QFlag, q); SetFlag(context, PState.QFlag, q);
} }
@@ -284,17 +280,10 @@ namespace ARMeilleure.Instructions
private static void EmitSetNzcv(ArmEmitterContext context, Operand t) private static void EmitSetNzcv(ArmEmitterContext context, Operand t)
{ {
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag)); Operand v = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.VFlag)), Const(1));
v = context.BitwiseAnd(v, Const(1)); Operand c = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.CFlag)), Const(1));
Operand z = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.ZFlag)), Const(1));
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag)); Operand n = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.NFlag)), Const(1));
c = context.BitwiseAnd(c, Const(1));
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
z = context.BitwiseAnd(z, Const(1));
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
n = context.BitwiseAnd(n, Const(1));
SetFlag(context, PState.VFlag, v); SetFlag(context, PState.VFlag, v);
SetFlag(context, PState.CFlag, c); SetFlag(context, PState.CFlag, c);
@@ -306,42 +295,32 @@ namespace ARMeilleure.Instructions
{ {
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
Operand vSh = context.ShiftLeft(GetFpFlag(FPState.VFlag), Const((int)FPState.VFlag)); Operand fpscr = Const(0);
Operand cSh = context.ShiftLeft(GetFpFlag(FPState.CFlag), Const((int)FPState.CFlag));
Operand zSh = context.ShiftLeft(GetFpFlag(FPState.ZFlag), Const((int)FPState.ZFlag));
Operand nSh = context.ShiftLeft(GetFpFlag(FPState.NFlag), Const((int)FPState.NFlag));
Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
{
if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag)))
{
fpscr = context.BitwiseOr(fpscr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
}
}
Operand fpscr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); SetIntA32(context, op.Rt, fpscr);
SetIntA32(context, op.Rt, context.BitwiseOr(nzcvSh, fpscr));
} }
private static void EmitSetFpscr(ArmEmitterContext context) private static void EmitSetFpscr(ArmEmitterContext context)
{ {
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
Operand t = GetIntA32(context, op.Rt); Operand fpscr = GetIntA32(context, op.Rt);
Operand v = context.ShiftRightUI(t, Const((int)FPState.VFlag)); for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
v = context.BitwiseAnd(v, Const(1)); {
if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag)))
Operand c = context.ShiftRightUI(t, Const((int)FPState.CFlag)); {
c = context.BitwiseAnd(c, Const(1)); SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpscr, Const(flag)), Const(1)));
}
Operand z = context.ShiftRightUI(t, Const((int)FPState.ZFlag)); }
z = context.BitwiseAnd(z, Const(1));
Operand n = context.ShiftRightUI(t, Const((int)FPState.NFlag));
n = context.BitwiseAnd(n, Const(1));
SetFpFlag(context, FPState.VFlag, v);
SetFpFlag(context, FPState.CFlag, c);
SetFpFlag(context, FPState.ZFlag, z);
SetFpFlag(context, FPState.NFlag, n);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr)), t);
} }
} }
} }

View File

@@ -72,29 +72,6 @@ namespace ARMeilleure.Instructions
return (ulong)GetContext().DczidEl0; return (ulong)GetContext().DczidEl0;
} }
public static ulong GetFpcr()
{
return (ulong)GetContext().Fpcr;
}
public static bool GetFpcrFz()
{
return (GetContext().Fpcr & FPCR.Fz) != 0;
}
public static ulong GetFpsr()
{
return (ulong)GetContext().Fpsr;
}
public static uint GetFpscr()
{
ExecutionContext context = GetContext();
return (uint)(context.Fpsr & FPSR.A32Mask & ~FPSR.Nzcv) |
(uint)(context.Fpcr & FPCR.A32Mask);
}
public static ulong GetTpidrEl0() public static ulong GetTpidrEl0()
{ {
return (ulong)GetContext().TpidrEl0; return (ulong)GetContext().TpidrEl0;
@@ -130,29 +107,6 @@ namespace ARMeilleure.Instructions
return GetContext().CntvctEl0; return GetContext().CntvctEl0;
} }
public static void SetFpcr(ulong value)
{
GetContext().Fpcr = (FPCR)value;
}
public static void SetFpsr(ulong value)
{
GetContext().Fpsr = (FPSR)value;
}
public static void SetFpsrQc()
{
GetContext().Fpsr |= FPSR.Qc;
}
public static void SetFpscr(uint fpscr)
{
ExecutionContext context = GetContext();
context.Fpsr = FPSR.A32Mask & (FPSR)fpscr;
context.Fpcr = FPCR.A32Mask & (FPCR)fpscr;
}
public static void SetTpidrEl0(ulong value) public static void SetTpidrEl0(ulong value)
{ {
GetContext().TpidrEl0 = (long)value; GetContext().TpidrEl0 = (long)value;

View File

@@ -91,76 +91,6 @@ namespace ARMeilleure.Instructions
} }
#endregion #endregion
#region "Rounding"
public static double Round(double value)
{
ExecutionContext context = NativeInterface.GetContext();
FPRoundingMode roundMode = context.Fpcr.GetRoundingMode();
if (roundMode == FPRoundingMode.ToNearest)
{
return Math.Round(value); // even
}
else if (roundMode == FPRoundingMode.TowardsPlusInfinity)
{
return Math.Ceiling(value);
}
else if (roundMode == FPRoundingMode.TowardsMinusInfinity)
{
return Math.Floor(value);
}
else /* if (roundMode == FPRoundingMode.TowardsZero) */
{
return Math.Truncate(value);
}
}
public static float RoundF(float value)
{
ExecutionContext context = NativeInterface.GetContext();
FPRoundingMode roundMode = context.Fpcr.GetRoundingMode();
if (roundMode == FPRoundingMode.ToNearest)
{
return MathF.Round(value); // even
}
else if (roundMode == FPRoundingMode.TowardsPlusInfinity)
{
return MathF.Ceiling(value);
}
else if (roundMode == FPRoundingMode.TowardsMinusInfinity)
{
return MathF.Floor(value);
}
else /* if (roundMode == FPRoundingMode.TowardsZero) */
{
return MathF.Truncate(value);
}
}
public static int FloatToInt32(float value)
{
return SatF32ToS32(RoundF(value));
}
public static int DoubleToInt32(double value)
{
return SatF64ToS32(Round(value));
}
public static uint FloatToUInt32(float value)
{
return SatF32ToU32(RoundF(value));
}
public static uint DoubleToUInt32(double value)
{
return SatF64ToU32(Round(value));
}
#endregion
#region "Saturation" #region "Saturation"
public static int SatF32ToS32(float value) public static int SatF32ToS32(float value)
{ {

View File

@@ -12,8 +12,8 @@ namespace ARMeilleure.Instructions
RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable(); RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
} }
internal static readonly byte[] RecipEstimateTable; public static readonly byte[] RecipEstimateTable;
internal static readonly byte[] RecipSqrtEstimateTable; public static readonly byte[] RecipSqrtEstimateTable;
private static byte[] BuildRecipEstimateTable() private static byte[] BuildRecipEstimateTable()
{ {
@@ -94,6 +94,13 @@ namespace ARMeilleure.Instructions
context.Fpsr |= (FPSR)(1 << (int)exc); 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 static class SoftFloat16

View File

@@ -36,10 +36,25 @@ namespace ARMeilleure.State
set => _nativeContext.SetPstate(value); set => _nativeContext.SetPstate(value);
} }
public FPCR Fpcr { get; set; } public FPSR Fpsr
public FPSR Fpsr { get; set; } {
get => (FPSR)_nativeContext.GetFPState((uint)FPSR.Mask);
set => _nativeContext.SetFPState((uint)value, (uint)FPSR.Mask);
}
public FPCR Fpcr
{
get => (FPCR)_nativeContext.GetFPState((uint)FPCR.Mask);
set => _nativeContext.SetFPState((uint)value, (uint)FPCR.Mask);
}
public FPCR StandardFpcrValue => (Fpcr & (FPCR.Ahp)) | FPCR.Dn | FPCR.Fz; public FPCR StandardFpcrValue => (Fpcr & (FPCR.Ahp)) | FPCR.Dn | FPCR.Fz;
public FPSCR Fpscr
{
get => (FPSCR)_nativeContext.GetFPState((uint)FPSCR.Mask);
set => _nativeContext.SetFPState((uint)value, (uint)FPSCR.Mask);
}
public bool IsAarch32 { get; set; } public bool IsAarch32 { get; set; }
internal ExecutionMode ExecutionMode internal ExecutionMode ExecutionMode

View File

@@ -5,21 +5,18 @@ namespace ARMeilleure.State
[Flags] [Flags]
public enum FPCR : uint public enum FPCR : uint
{ {
Ioe = 1u << 8,
Dze = 1u << 9,
Ofe = 1u << 10,
Ufe = 1u << 11, Ufe = 1u << 11,
Ixe = 1u << 12,
Ide = 1u << 15,
RMode0 = 1u << 22,
RMode1 = 1u << 23,
Fz = 1u << 24, Fz = 1u << 24,
Dn = 1u << 25, Dn = 1u << 25,
Ahp = 1u << 26, Ahp = 1u << 26,
A32Mask = 0x07FF9F00u Mask = Ahp | Dn | Fz | RMode1 | RMode0 | Ide | Ixe | Ufe | Ofe | Dze | Ioe // 0x07C09F00u
}
public static class FPCRExtensions
{
private const int RModeShift = 22;
public static FPRoundingMode GetRoundingMode(this FPCR fpcr)
{
return (FPRoundingMode)(((int)fpcr >> RModeShift) & 3);
}
} }
} }

View File

@@ -0,0 +1,15 @@
using System;
namespace ARMeilleure.State
{
[Flags]
public enum FPSCR : uint
{
V = 1u << 28,
C = 1u << 29,
Z = 1u << 30,
N = 1u << 31,
Mask = N | Z | C | V | FPSR.Mask | FPCR.Mask // 0xFFC09F9Fu
}
}

View File

@@ -5,11 +5,14 @@ namespace ARMeilleure.State
[Flags] [Flags]
public enum FPSR : uint public enum FPSR : uint
{ {
Ioc = 1u << 0,
Dzc = 1u << 1,
Ofc = 1u << 2,
Ufc = 1u << 3, Ufc = 1u << 3,
Qc = 1u << 27, Ixc = 1u << 4,
Idc = 1u << 7,
Qc = 1u << 27,
Nzcv = (1u << 31) | (1u << 30) | (1u << 29) | (1u << 28), Mask = Qc | Idc | Ixc | Ufc | Ofc | Dzc | Ioc // 0x0800009Fu
A32Mask = 0xF800009Fu
} }
} }

View File

@@ -2,9 +2,30 @@
{ {
public enum FPState public enum FPState
{ {
// FPSR Flags.
IocFlag = 0,
DzcFlag = 1,
OfcFlag = 2,
UfcFlag = 3,
IxcFlag = 4,
IdcFlag = 7,
QcFlag = 27,
VFlag = 28, VFlag = 28,
CFlag = 29, CFlag = 29,
ZFlag = 30, ZFlag = 30,
NFlag = 31 NFlag = 31,
// FPCR Flags.
IoeFlag = 8,
DzeFlag = 9,
OfeFlag = 10,
UfeFlag = 11,
IxeFlag = 12,
IdeFlag = 15,
RMode0Flag = 22,
RMode1Flag = 23,
FzFlag = 24,
DnFlag = 25,
AhpFlag = 26
} }
} }

View File

@@ -140,6 +140,34 @@ namespace ARMeilleure.State
GetStorage().FpFlags[(int)flag] = value ? 1u : 0u; GetStorage().FpFlags[(int)flag] = value ? 1u : 0u;
} }
public unsafe uint GetFPState(uint mask = uint.MaxValue)
{
uint value = 0;
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
{
uint bit = 1u << flag;
if ((mask & bit) == bit)
{
value |= GetStorage().FpFlags[flag] != 0 ? bit : 0u;
}
}
return value;
}
public unsafe void SetFPState(uint value, uint mask = uint.MaxValue)
{
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
{
uint bit = 1u << flag;
if ((mask & bit) == bit)
{
GetStorage().FpFlags[flag] = (value & bit) == bit ? 1u : 0u;
}
}
}
public int GetCounter() => GetStorage().Counter; public int GetCounter() => GetStorage().Counter;
public void SetCounter(int value) => GetStorage().Counter = value; public void SetCounter(int value) => GetStorage().Counter = value;

View File

@@ -109,10 +109,6 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only.
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
@@ -124,10 +120,6 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr))); // A32 only.
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only. SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
@@ -151,12 +143,8 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32))); // A32 only.
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))); // A32 only.
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32))); // A32 only.
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))); // A32 only.
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
@@ -165,8 +153,6 @@ namespace ARMeilleure.Translation
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));

View File

@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 3700; //! To be incremented manually for each change to the ARMeilleure project. private const uint InternalVersion = 3703; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0"; private const string ActualDir = "0";
private const string BackupDir = "1"; private const string BackupDir = "1";

View File

@@ -68,6 +68,8 @@ namespace Ryujinx.Graphics.Vulkan
private bool _tfEnabled; private bool _tfEnabled;
private bool _tfActive; private bool _tfActive;
private PipelineColorBlendAttachmentState[] _storedBlend;
public ulong DrawCount { get; private set; } public ulong DrawCount { get; private set; }
public unsafe PipelineBase(VulkanRenderer gd, Device device) public unsafe PipelineBase(VulkanRenderer gd, Device device)
@@ -104,6 +106,8 @@ namespace Ryujinx.Graphics.Vulkan
_newState.Initialize(); _newState.Initialize();
_newState.LineWidth = 1f; _newState.LineWidth = 1f;
_newState.SamplesCount = 1; _newState.SamplesCount = 1;
_storedBlend = new PipelineColorBlendAttachmentState[8];
} }
public void Initialize() public void Initialize()
@@ -498,13 +502,28 @@ namespace Ryujinx.Graphics.Vulkan
{ {
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index]; ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
vkBlend.BlendEnable = blend.Enable; if (blend.Enable)
vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert(); {
vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert(); vkBlend.BlendEnable = blend.Enable;
vkBlend.ColorBlendOp = blend.ColorOp.Convert(); vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert(); vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert(); vkBlend.ColorBlendOp = blend.ColorOp.Convert();
vkBlend.AlphaBlendOp = blend.AlphaOp.Convert(); vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert();
vkBlend.AlphaBlendOp = blend.AlphaOp.Convert();
}
else
{
vkBlend = new PipelineColorBlendAttachmentState(
colorWriteMask: vkBlend.ColorWriteMask);
}
if (vkBlend.ColorWriteMask == 0)
{
_storedBlend[index] = vkBlend;
vkBlend = new PipelineColorBlendAttachmentState();
}
_newState.BlendConstantR = blend.BlendConstant.Red; _newState.BlendConstantR = blend.BlendConstant.Red;
_newState.BlendConstantG = blend.BlendConstant.Green; _newState.BlendConstantG = blend.BlendConstant.Green;
@@ -669,8 +688,25 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i]; ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
var newMask = (ColorComponentFlags)componentMask[i];
vkBlend.ColorWriteMask = (ColorComponentFlags)componentMask[i]; // When color write mask is 0, remove all blend state to help the pipeline cache.
// Restore it when the mask becomes non-zero.
if (vkBlend.ColorWriteMask != newMask)
{
if (newMask == 0)
{
_storedBlend[i] = vkBlend;
vkBlend = new PipelineColorBlendAttachmentState();
}
else if (vkBlend.ColorWriteMask == 0)
{
vkBlend = _storedBlend[i];
}
}
vkBlend.ColorWriteMask = newMask;
if (componentMask[i] != 0) if (componentMask[i] != 0)
{ {

View File

@@ -257,15 +257,23 @@ namespace Ryujinx.Graphics.Vulkan
{ {
var blend = state.BlendDescriptors[i]; var blend = state.BlendDescriptors[i];
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState( if (blend.Enable && state.ColorWriteMask[i] != 0)
blend.Enable, {
blend.ColorSrcFactor.Convert(), pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
blend.ColorDstFactor.Convert(), blend.Enable,
blend.ColorOp.Convert(), blend.ColorSrcFactor.Convert(),
blend.AlphaSrcFactor.Convert(), blend.ColorDstFactor.Convert(),
blend.AlphaDstFactor.Convert(), blend.ColorOp.Convert(),
blend.AlphaOp.Convert(), blend.AlphaSrcFactor.Convert(),
(ColorComponentFlags)state.ColorWriteMask[i]); blend.AlphaDstFactor.Convert(),
blend.AlphaOp.Convert(),
(ColorComponentFlags)state.ColorWriteMask[i]);
}
else
{
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
colorWriteMask: (ColorComponentFlags)state.ColorWriteMask[i]);
}
} }
int maxAttachmentIndex = 0; int maxAttachmentIndex = 0;

View File

@@ -22,7 +22,8 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
// outside of the AccountManager. // outside of the AccountManager.
private readonly HorizonClient _horizonClient; private readonly HorizonClient _horizonClient;
private ConcurrentDictionary<string, UserProfile> _profiles; private readonly ConcurrentDictionary<string, UserProfile> _profiles;
private UserProfile[] _storedOpenedUsers;
public UserProfile LastOpenedUser { get; private set; } public UserProfile LastOpenedUser { get; private set; }
@@ -31,6 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
_horizonClient = horizonClient; _horizonClient = horizonClient;
_profiles = new ConcurrentDictionary<string, UserProfile>(); _profiles = new ConcurrentDictionary<string, UserProfile>();
_storedOpenedUsers = Array.Empty<UserProfile>();
_accountSaveDataManager = new AccountSaveDataManager(_profiles); _accountSaveDataManager = new AccountSaveDataManager(_profiles);
@@ -44,9 +46,9 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
} }
else else
{ {
UserId commandLineUserProfileOverride = default; UserId commandLineUserProfileOverride = default;
if (!string.IsNullOrEmpty(initialProfileName)) if (!string.IsNullOrEmpty(initialProfileName))
{ {
commandLineUserProfileOverride = _profiles.Values.FirstOrDefault(x => x.Name == initialProfileName)?.UserId ?? default; commandLineUserProfileOverride = _profiles.Values.FirstOrDefault(x => x.Name == initialProfileName)?.UserId ?? default;
if (commandLineUserProfileOverride.IsNull) if (commandLineUserProfileOverride.IsNull)
Logger.Warning?.Print(LogClass.Application, $"The command line specified profile named '{initialProfileName}' was not found"); Logger.Warning?.Print(LogClass.Application, $"The command line specified profile named '{initialProfileName}' was not found");
@@ -221,6 +223,16 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
return _profiles.Values.Where(x => x.AccountState == AccountState.Open); return _profiles.Values.Where(x => x.AccountState == AccountState.Open);
} }
internal IEnumerable<UserProfile> GetStoredOpenedUsers()
{
return _storedOpenedUsers;
}
internal void StoreOpenedUsers()
{
_storedOpenedUsers = _profiles.Values.Where(x => x.AccountState == AccountState.Open).ToArray();
}
internal UserProfile GetFirst() internal UserProfile GetFirst()
{ {
return _profiles.First().Value; return _profiles.First().Value;

View File

@@ -162,7 +162,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
public ResultCode StoreOpenContext(ServiceCtx context) public ResultCode StoreOpenContext(ServiceCtx context)
{ {
Logger.Stub?.PrintStub(LogClass.ServiceAcc); context.Device.System.AccountManager.StoreOpenedUsers();
return ResultCode.Success; return ResultCode.Success;
} }

View File

@@ -201,6 +201,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
return ResultCode.Success; return ResultCode.Success;
} }
public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
{
return WriteUserList(context, context.Device.System.AccountManager.GetStoredOpenedUsers());
}
public ResultCode ListQualifiedUsers(ServiceCtx context) public ResultCode ListQualifiedUsers(ServiceCtx context)
{ {
// TODO: Determine how users are "qualified". We assume all users are "qualified" for now. // TODO: Determine how users are "qualified". We assume all users are "qualified" for now.

View File

@@ -1,5 +1,4 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService; using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
using Ryujinx.HLE.HOS.Services.Arp; using Ryujinx.HLE.HOS.Services.Arp;
@@ -139,20 +138,21 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
return _applicationServiceServer.ClearSaveDataThumbnail(context); return _applicationServiceServer.ClearSaveDataThumbnail(context);
} }
[CommandHipc(130)] // 5.0.0+
// LoadOpenContext(nn::account::Uid)
public ResultCode LoadOpenContext(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
return ResultCode.Success;
}
[CommandHipc(60)] // 5.0.0-5.1.0
[CommandHipc(131)] // 6.0.0+ [CommandHipc(131)] // 6.0.0+
// ListOpenContextStoredUsers() -> array<nn::account::Uid, 0xa> // ListOpenContextStoredUsers() -> array<nn::account::Uid, 0xa>
public ResultCode ListOpenContextStoredUsers(ServiceCtx context) public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
{ {
ulong outputPosition = context.Request.RecvListBuff[0].Position; return _applicationServiceServer.ListOpenContextStoredUsers(context);
ulong outputSize = context.Request.RecvListBuff[0].Size;
MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
// TODO: This seems to write stored userids of the OpenContext in the buffer. We needs to determine them.
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
return ResultCode.Success;
} }
[CommandHipc(141)] // 6.0.0+ [CommandHipc(141)] // 6.0.0+

View File

@@ -181,7 +181,11 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
} }
} }
public bool TryGetCertificates(ReadOnlySpan<CaCertificateId> ids, out CertStoreEntry[] entries) public bool TryGetCertificates(
ReadOnlySpan<CaCertificateId> ids,
out CertStoreEntry[] entries,
out bool hasAllCertificates,
out int requiredSize)
{ {
lock (_lock) lock (_lock)
{ {
@@ -190,7 +194,8 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
throw new InvalidSystemResourceException(CertStoreTitleMissingErrorMessage); throw new InvalidSystemResourceException(CertStoreTitleMissingErrorMessage);
} }
bool hasAllCertificates = false; requiredSize = 0;
hasAllCertificates = false;
foreach (CaCertificateId id in ids) foreach (CaCertificateId id in ids)
{ {
@@ -205,12 +210,14 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
if (hasAllCertificates) if (hasAllCertificates)
{ {
entries = new CertStoreEntry[_certificates.Count]; entries = new CertStoreEntry[_certificates.Count];
requiredSize = (_certificates.Count + 1) * Unsafe.SizeOf<BuiltInCertificateInfo>();
int i = 0; int i = 0;
foreach (CertStoreEntry entry in _certificates.Values) foreach (CertStoreEntry entry in _certificates.Values)
{ {
entries[i++] = entry; entries[i++] = entry;
requiredSize += (entry.Data.Length + 3) & ~3;
} }
return true; return true;
@@ -218,6 +225,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
else else
{ {
entries = new CertStoreEntry[ids.Length]; entries = new CertStoreEntry[ids.Length];
requiredSize = ids.Length * Unsafe.SizeOf<BuiltInCertificateInfo>();
for (int i = 0; i < ids.Length; i++) for (int i = 0; i < ids.Length; i++)
{ {
@@ -227,6 +235,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
} }
entries[i] = entry; entries[i] = entry;
requiredSize += (entry.Data.Length + 3) & ~3;
} }
return true; return true;

View File

@@ -29,42 +29,40 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
return ResultCode.Success; return ResultCode.Success;
} }
private uint ComputeCertificateBufferSizeRequired(ReadOnlySpan<BuiltInCertificateManager.CertStoreEntry> entries)
{
uint totalSize = 0;
for (int i = 0; i < entries.Length; i++)
{
totalSize += (uint)Unsafe.SizeOf<BuiltInCertificateInfo>();
totalSize += (uint)entries[i].Data.Length;
}
return totalSize;
}
[CommandHipc(2)] [CommandHipc(2)]
// GetCertificates(buffer<CaCertificateId, 5> ids) -> (u32 certificates_count, buffer<bytes, 6> certificates) // GetCertificates(buffer<CaCertificateId, 5> ids) -> (u32 certificates_count, buffer<bytes, 6> certificates)
public ResultCode GetCertificates(ServiceCtx context) public ResultCode GetCertificates(ServiceCtx context)
{ {
ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size)); ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size));
if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out BuiltInCertificateManager.CertStoreEntry[] entries)) if (!BuiltInCertificateManager.Instance.TryGetCertificates(
ids,
out BuiltInCertificateManager.CertStoreEntry[] entries,
out bool hasAllCertificates,
out int requiredSize))
{ {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
if (ComputeCertificateBufferSizeRequired(entries) > context.Request.ReceiveBuff[0].Size) if ((uint)requiredSize > (uint)context.Request.ReceiveBuff[0].Size)
{ {
return ResultCode.InvalidCertBufSize; return ResultCode.InvalidCertBufSize;
} }
int infosCount = entries.Length;
if (hasAllCertificates)
{
infosCount++;
}
using (WritableRegion region = context.Memory.GetWritableRegion(context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size)) using (WritableRegion region = context.Memory.GetWritableRegion(context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size))
{ {
Span<byte> rawData = region.Memory.Span; Span<byte> rawData = region.Memory.Span;
Span<BuiltInCertificateInfo> infos = MemoryMarshal.Cast<byte, BuiltInCertificateInfo>(rawData)[..entries.Length]; Span<BuiltInCertificateInfo> infos = MemoryMarshal.Cast<byte, BuiltInCertificateInfo>(rawData)[..infosCount];
Span<byte> certificatesData = rawData[(Unsafe.SizeOf<BuiltInCertificateInfo>() * entries.Length)..]; Span<byte> certificatesData = rawData[(Unsafe.SizeOf<BuiltInCertificateInfo>() * infosCount)..];
for (int i = 0; i < infos.Length; i++) for (int i = 0; i < entries.Length; i++)
{ {
entries[i].Data.CopyTo(certificatesData); entries[i].Data.CopyTo(certificatesData);
@@ -78,6 +76,17 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
certificatesData = certificatesData[entries[i].Data.Length..]; certificatesData = certificatesData[entries[i].Data.Length..];
} }
if (hasAllCertificates)
{
infos[entries.Length] = new BuiltInCertificateInfo
{
Id = CaCertificateId.All,
Status = TrustedCertStatus.Invalid,
CertificateDataSize = 0,
CertificateDataOffset = 0
};
}
} }
context.ResponseData.Write(entries.Length); context.ResponseData.Write(entries.Length);
@@ -91,12 +100,12 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
{ {
ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size)); ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size));
if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out BuiltInCertificateManager.CertStoreEntry[] entries)) if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out _, out _, out int requiredSize))
{ {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
context.ResponseData.Write(ComputeCertificateBufferSizeRequired(entries)); context.ResponseData.Write(requiredSize);
return ResultCode.Success; return ResultCode.Success;
} }

View File

@@ -162,7 +162,7 @@ namespace Ryujinx.Tests.Cpu
_context.SetPstateFlag(PState.ZFlag, zero); _context.SetPstateFlag(PState.ZFlag, zero);
_context.SetPstateFlag(PState.NFlag, negative); _context.SetPstateFlag(PState.NFlag, negative);
SetFpscr((uint)fpscr); _context.Fpscr = (FPSCR)fpscr;
_context.SetPstateFlag(PState.TFlag, thumb); _context.SetPstateFlag(PState.TFlag, thumb);
@@ -467,7 +467,7 @@ namespace Ryujinx.Tests.Cpu
Assert.That(_context.GetPstateFlag(PState.NFlag), Is.EqualTo(_unicornEmu.NegativeFlag), "NFlag"); Assert.That(_context.GetPstateFlag(PState.NFlag), Is.EqualTo(_unicornEmu.NegativeFlag), "NFlag");
}); });
Assert.That((int)GetFpscr() & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpscr & (int)fpsrMask), "Fpscr"); Assert.That((int)_context.Fpscr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpscr & (int)fpsrMask), "Fpscr");
if (_usingMemory) if (_usingMemory)
{ {
@@ -650,28 +650,5 @@ namespace Ryujinx.Tests.Cpu
return rnd & 0x800FFFFFFFFFFFFFul; return rnd & 0x800FFFFFFFFFFFFFul;
} }
private uint GetFpscr()
{
uint fpscr = (uint)(_context.Fpsr & FPSR.A32Mask & ~FPSR.Nzcv) | (uint)(_context.Fpcr & FPCR.A32Mask);
fpscr |= _context.GetFPstateFlag(FPState.NFlag) ? (1u << (int)FPState.NFlag) : 0;
fpscr |= _context.GetFPstateFlag(FPState.ZFlag) ? (1u << (int)FPState.ZFlag) : 0;
fpscr |= _context.GetFPstateFlag(FPState.CFlag) ? (1u << (int)FPState.CFlag) : 0;
fpscr |= _context.GetFPstateFlag(FPState.VFlag) ? (1u << (int)FPState.VFlag) : 0;
return fpscr;
}
private void SetFpscr(uint fpscr)
{
_context.Fpsr = FPSR.A32Mask & (FPSR)fpscr;
_context.Fpcr = FPCR.A32Mask & (FPCR)fpscr;
_context.SetFPstateFlag(FPState.NFlag, (fpscr & (1u << (int)FPState.NFlag)) != 0);
_context.SetFPstateFlag(FPState.ZFlag, (fpscr & (1u << (int)FPState.ZFlag)) != 0);
_context.SetFPstateFlag(FPState.CFlag, (fpscr & (1u << (int)FPState.CFlag)) != 0);
_context.SetFPstateFlag(FPState.VFlag, (fpscr & (1u << (int)FPState.VFlag)) != 0);
}
} }
} }