Add curly braces back to the if statements
This commit is contained in:
parent
c934bc47d5
commit
2019baffc4
218 changed files with 7140 additions and 1387 deletions
|
@ -6,7 +6,10 @@ namespace ChocolArm64
|
|||
{
|
||||
int count = 0;
|
||||
|
||||
for (int bit = 0; bit < 64; bit++) count += (int)(value >> bit) & 1;
|
||||
for (int bit = 0; bit < 64; bit++)
|
||||
{
|
||||
count += (int)(value >> bit) & 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -14,7 +17,12 @@ namespace ChocolArm64
|
|||
public static int HighestBitSet32(int value)
|
||||
{
|
||||
for (int bit = 31; bit >= 0; bit--)
|
||||
if (((value >> bit) & 1) != 0) return bit;
|
||||
{
|
||||
if (((value >> bit) & 1) != 0)
|
||||
{
|
||||
return bit;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -30,7 +38,10 @@ namespace ChocolArm64
|
|||
{
|
||||
long output = 0;
|
||||
|
||||
for (int bit = 0; bit < 64; bit += size) output |= bits << bit;
|
||||
for (int bit = 0; bit < 64; bit += size)
|
||||
{
|
||||
output |= bits << bit;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -530,7 +530,10 @@ namespace ChocolArm64
|
|||
|
||||
#region "Generate InstA64FastLookup Table (AArch64)"
|
||||
var tmp = new List<InstInfo>[_fastLookupSize];
|
||||
for (int i = 0; i < _fastLookupSize; i++) tmp[i] = new List<InstInfo>();
|
||||
for (int i = 0; i < _fastLookupSize; i++)
|
||||
{
|
||||
tmp[i] = new List<InstInfo>();
|
||||
}
|
||||
|
||||
foreach (var inst in _allInstA64)
|
||||
{
|
||||
|
@ -538,10 +541,18 @@ namespace ChocolArm64
|
|||
int value = ToFastLookupIndex(inst.Value);
|
||||
|
||||
for (int i = 0; i < _fastLookupSize; i++)
|
||||
if ((i & mask) == value) tmp[i].Add(inst);
|
||||
{
|
||||
if ((i & mask) == value)
|
||||
{
|
||||
tmp[i].Add(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _fastLookupSize; i++) _instA64FastLookup[i] = tmp[i].ToArray();
|
||||
for (int i = 0; i < _fastLookupSize; i++)
|
||||
{
|
||||
_instA64FastLookup[i] = tmp[i].ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -635,9 +646,15 @@ namespace ChocolArm64
|
|||
{
|
||||
int mask = 0;
|
||||
|
||||
for (int x = 0; x < xBits; x++) mask |= ((index >> x) & 1) << xPos[x];
|
||||
for (int x = 0; x < xBits; x++)
|
||||
{
|
||||
mask |= ((index >> x) & 1) << xPos[x];
|
||||
}
|
||||
|
||||
if (mask != blacklisted) InsertInst(xMask, value | mask, inst, mode);
|
||||
if (mask != blacklisted)
|
||||
{
|
||||
InsertInst(xMask, value | mask, inst, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -650,9 +667,13 @@ namespace ChocolArm64
|
|||
InstInfo info = new InstInfo(xMask, value, inst);
|
||||
|
||||
if (mode == AExecutionMode.AArch64)
|
||||
{
|
||||
_allInstA64.Add(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
_allInstA32.Add(info);
|
||||
}
|
||||
}
|
||||
|
||||
public static AInst GetInstA32(int opCode)
|
||||
|
@ -673,7 +694,12 @@ namespace ChocolArm64
|
|||
private static AInst GetInstFromList(IEnumerable<InstInfo> instList, int opCode)
|
||||
{
|
||||
foreach (var node in instList)
|
||||
if ((opCode & node.Mask) == node.Value) return node.Inst;
|
||||
{
|
||||
if ((opCode & node.Mask) == node.Value)
|
||||
{
|
||||
return node.Inst;
|
||||
}
|
||||
}
|
||||
|
||||
return AInst.Undefined;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,10 @@ namespace ChocolArm64
|
|||
|
||||
public bool Execute()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _isExecuting, 1) == 1) return false;
|
||||
if (Interlocked.Exchange(ref _isExecuting, 1) == 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Work.Start();
|
||||
|
||||
|
|
|
@ -36,9 +36,15 @@ namespace ChocolArm64
|
|||
|
||||
public ATranslatedSub(DynamicMethod method, List<ARegister> Params)
|
||||
{
|
||||
if (method == null) throw new ArgumentNullException(nameof(method));
|
||||
if (method == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(method));
|
||||
}
|
||||
|
||||
if (Params == null) throw new ArgumentNullException(nameof(Params));
|
||||
if (Params == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Params));
|
||||
}
|
||||
|
||||
Method = method;
|
||||
this.Params = Params.AsReadOnly();
|
||||
|
@ -63,8 +69,13 @@ namespace ChocolArm64
|
|||
FixedArgTypes[index] = paramType;
|
||||
|
||||
if (paramType == typeof(AThreadState))
|
||||
{
|
||||
StateArgIdx = index;
|
||||
else if (paramType == typeof(AMemory)) MemoryArgIdx = index;
|
||||
}
|
||||
else if (paramType == typeof(AMemory))
|
||||
{
|
||||
MemoryArgIdx = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +139,10 @@ namespace ChocolArm64
|
|||
{
|
||||
_type = type;
|
||||
|
||||
if (type == ATranslatedSubType.SubTier0) _needsReJit = true;
|
||||
if (type == ATranslatedSubType.SubTier0)
|
||||
{
|
||||
_needsReJit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkForReJit()
|
||||
|
|
|
@ -30,9 +30,13 @@ namespace ChocolArm64
|
|||
AMemory memory = thread.Memory;
|
||||
|
||||
if (state.ExecutionMode == AExecutionMode.AArch32)
|
||||
{
|
||||
ExecuteSubroutineA32(state, memory);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecuteSubroutineA64(state, memory, position);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteSubroutineA32(AThreadState state, AMemory memory)
|
||||
|
@ -50,11 +54,20 @@ namespace ChocolArm64
|
|||
{
|
||||
do
|
||||
{
|
||||
if (EnableCpuTrace) CpuTrace?.Invoke(this, new ACpuTraceEventArgs(position));
|
||||
if (EnableCpuTrace)
|
||||
{
|
||||
CpuTrace?.Invoke(this, new ACpuTraceEventArgs(position));
|
||||
}
|
||||
|
||||
if (!_cache.TryGetSubroutine(position, out ATranslatedSub sub)) sub = TranslateTier0(state, memory, position);
|
||||
if (!_cache.TryGetSubroutine(position, out ATranslatedSub sub))
|
||||
{
|
||||
sub = TranslateTier0(state, memory, position);
|
||||
}
|
||||
|
||||
if (sub.ShouldReJit()) TranslateTier1(state, memory, position);
|
||||
if (sub.ShouldReJit())
|
||||
{
|
||||
TranslateTier1(state, memory, position);
|
||||
}
|
||||
|
||||
position = sub.Execute(state, memory);
|
||||
}
|
||||
|
@ -101,7 +114,10 @@ namespace ChocolArm64
|
|||
|
||||
AILEmitterCtx context = new AILEmitterCtx(_cache, graph, root, subName);
|
||||
|
||||
if (context.CurrBlock.Position != position) context.Emit(OpCodes.Br, context.GetLabel(position));
|
||||
if (context.CurrBlock.Position != position)
|
||||
{
|
||||
context.Emit(OpCodes.Br, context.GetLabel(position));
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -112,8 +128,15 @@ namespace ChocolArm64
|
|||
//Mark all methods that calls this method for ReJiting,
|
||||
//since we can now call it directly which is faster.
|
||||
if (_cache.TryGetSubroutine(position, out ATranslatedSub oldSub))
|
||||
{
|
||||
foreach (long callerPos in oldSub.GetCallerPositions())
|
||||
if (_cache.TryGetSubroutine(position, out ATranslatedSub callerSub)) callerSub.MarkForReJit();
|
||||
{
|
||||
if (_cache.TryGetSubroutine(position, out ATranslatedSub callerSub))
|
||||
{
|
||||
callerSub.MarkForReJit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ATranslatedSub subroutine = context.GetSubroutine();
|
||||
|
||||
|
@ -131,7 +154,10 @@ namespace ChocolArm64
|
|||
{
|
||||
int size = 0;
|
||||
|
||||
foreach (ABlock block in graph) size += block.OpCodes.Count;
|
||||
foreach (ABlock block in graph)
|
||||
{
|
||||
size += block.OpCodes.Count;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -92,7 +92,9 @@ namespace ChocolArm64
|
|||
if (_cache.TryGetValue(position, out CacheBucket bucket))
|
||||
{
|
||||
if (bucket.CallCount++ > MinCallCountForUpdate)
|
||||
{
|
||||
if (Monitor.TryEnter(_sortedCache))
|
||||
{
|
||||
try
|
||||
{
|
||||
bucket.CallCount = 0;
|
||||
|
@ -105,6 +107,8 @@ namespace ChocolArm64
|
|||
{
|
||||
Monitor.Exit(_sortedCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subroutine = bucket.Subroutine;
|
||||
|
||||
|
@ -121,17 +125,24 @@ namespace ChocolArm64
|
|||
int timestamp = Environment.TickCount;
|
||||
|
||||
while (_totalSize > MaxTotalSize)
|
||||
{
|
||||
lock (_sortedCache)
|
||||
{
|
||||
LinkedListNode<long> node = _sortedCache.First;
|
||||
|
||||
if (node == null) break;
|
||||
if (node == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CacheBucket bucket = _cache[node.Value];
|
||||
|
||||
int timeDelta = RingDelta(bucket.Timestamp, timestamp);
|
||||
|
||||
if ((uint)timeDelta <= (uint)MinTimeDelta) break;
|
||||
if ((uint)timeDelta <= (uint)MinTimeDelta)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (_cache.TryRemove(node.Value, out bucket))
|
||||
{
|
||||
|
@ -140,14 +151,19 @@ namespace ChocolArm64
|
|||
_sortedCache.Remove(bucket.Node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int RingDelta(int old, int New)
|
||||
{
|
||||
if ((uint)New < (uint)old)
|
||||
{
|
||||
return New + ~old + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return New - old;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,7 +24,10 @@ namespace ChocolArm64.Decoder
|
|||
|
||||
public AOpCode GetLastOp()
|
||||
{
|
||||
if (OpCodes.Count > 0) return OpCodes[OpCodes.Count - 1];
|
||||
if (OpCodes.Count > 0)
|
||||
{
|
||||
return OpCodes[OpCodes.Count - 1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -74,14 +74,20 @@ namespace ChocolArm64.Decoder
|
|||
if (lastOp is AOpCodeBImm op)
|
||||
{
|
||||
if (op.Emitter == AInstEmit.Bl)
|
||||
{
|
||||
hasCachedSub = cache.HasSubroutine(op.Imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
current.Branch = Enqueue(op.Imm);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(lastOp is AOpCodeBImmAl ||
|
||||
lastOp is AOpCodeBReg) || hasCachedSub)
|
||||
{
|
||||
current.Next = Enqueue(current.EndPosition);
|
||||
}
|
||||
}
|
||||
|
||||
//If we have on the graph two blocks with the same end position,
|
||||
|
@ -120,8 +126,12 @@ namespace ChocolArm64.Decoder
|
|||
ulong firstPos = ulong.MaxValue;
|
||||
|
||||
foreach (ABlock block in visited.Values)
|
||||
{
|
||||
if (firstPos > (ulong)block.Position)
|
||||
{
|
||||
firstPos = (ulong)block.Position;
|
||||
}
|
||||
}
|
||||
|
||||
ABlock current = visited[(long)firstPos];
|
||||
|
||||
|
@ -180,20 +190,30 @@ namespace ChocolArm64.Decoder
|
|||
AInst inst;
|
||||
|
||||
if (state.ExecutionMode == AExecutionMode.AArch64)
|
||||
{
|
||||
inst = AOpCodeTable.GetInstA64(opCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
inst = AOpCodeTable.GetInstA32(opCode);
|
||||
}
|
||||
|
||||
AOpCode decodedOpCode = new AOpCode(AInst.Undefined, position, opCode);
|
||||
|
||||
if (inst.Type != null) decodedOpCode = MakeOpCode(inst.Type, inst, position, opCode);
|
||||
if (inst.Type != null)
|
||||
{
|
||||
decodedOpCode = MakeOpCode(inst.Type, inst, position, opCode);
|
||||
}
|
||||
|
||||
return decodedOpCode;
|
||||
}
|
||||
|
||||
private static AOpCode MakeOpCode(Type type, AInst inst, long position, int opCode)
|
||||
{
|
||||
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||
if (type == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
OpActivator createInstance = _opActivators.GetOrAdd(type, CacheOpActivator);
|
||||
|
||||
|
|
|
@ -25,7 +25,10 @@ namespace ChocolArm64.Decoder
|
|||
|
||||
int length = ABitUtils.HighestBitSet32((~immS & 0x3f) | (n << 6));
|
||||
|
||||
if (length < 1 || sf == 0 && n != 0) return BitMask.Invalid;
|
||||
if (length < 1 || sf == 0 && n != 0)
|
||||
{
|
||||
return BitMask.Invalid;
|
||||
}
|
||||
|
||||
int size = 1 << length;
|
||||
|
||||
|
@ -34,7 +37,10 @@ namespace ChocolArm64.Decoder
|
|||
int s = immS & levels;
|
||||
int r = immR & levels;
|
||||
|
||||
if (immediate && s == levels) return BitMask.Invalid;
|
||||
if (immediate && s == levels)
|
||||
{
|
||||
return BitMask.Invalid;
|
||||
}
|
||||
|
||||
long wMask = ABitUtils.FillWithOnes(s + 1);
|
||||
long mask = ABitUtils.FillWithOnes(((s - r) & levels) + 1);
|
||||
|
@ -72,7 +78,10 @@ namespace ChocolArm64.Decoder
|
|||
long eBit = (imm >> 6) & 1;
|
||||
long sBit = (imm >> 7) & 1;
|
||||
|
||||
if (eBit != 0) value |= ((1L << (e - 3)) - 1) << (f + 2);
|
||||
if (eBit != 0)
|
||||
{
|
||||
value |= ((1L << (e - 3)) - 1) << (f + 2);
|
||||
}
|
||||
|
||||
value |= (eBit ^ 1) << (f + e - 1);
|
||||
value |= sBit << (f + e);
|
||||
|
|
|
@ -33,12 +33,19 @@ namespace ChocolArm64.Decoder
|
|||
|
||||
//Unscaled and Unprivileged doesn't write back,
|
||||
//but they do use the 9-bits Signed Immediate.
|
||||
if (Unscaled) WBack = false;
|
||||
if (Unscaled)
|
||||
{
|
||||
WBack = false;
|
||||
}
|
||||
|
||||
if (WBack || Unscaled)
|
||||
{
|
||||
Imm = (opCode << 43) >> 55;
|
||||
}
|
||||
else
|
||||
{
|
||||
Imm = ((opCode >> 10) & 0xfff) << Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -89,9 +89,13 @@ namespace ChocolArm64.Decoder
|
|||
private static long ShlOnes(long value, int shift)
|
||||
{
|
||||
if (shift != 0)
|
||||
{
|
||||
return (value << shift) | (long)(ulong.MaxValue >> (64 - shift));
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,10 @@ namespace ChocolArm64.Decoder
|
|||
{
|
||||
Size |= (opCode >> 21) & 4;
|
||||
|
||||
if (!WBack && !Unscaled && Size >= 4) Imm <<= 4;
|
||||
if (!WBack && !Unscaled && Size >= 4)
|
||||
{
|
||||
Imm <<= 4;
|
||||
}
|
||||
|
||||
Extend64 = false;
|
||||
}
|
||||
|
|
|
@ -208,7 +208,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int idx = 0; idx <= 15; idx++) outState[_isrPerm[idx]] = inState[idx];
|
||||
for (int idx = 0; idx <= 15; idx++)
|
||||
{
|
||||
outState[_isrPerm[idx]] = inState[idx];
|
||||
}
|
||||
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
|
@ -222,7 +225,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int idx = 0; idx <= 15; idx++) outState[idx] = _invSBox[inState[idx]];
|
||||
for (int idx = 0; idx <= 15; idx++)
|
||||
{
|
||||
outState[idx] = _invSBox[inState[idx]];
|
||||
}
|
||||
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
|
@ -263,7 +269,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int idx = 0; idx <= 15; idx++) outState[_srPerm[idx]] = inState[idx];
|
||||
for (int idx = 0; idx <= 15; idx++)
|
||||
{
|
||||
outState[_srPerm[idx]] = inState[idx];
|
||||
}
|
||||
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
|
@ -277,7 +286,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int idx = 0; idx <= 15; idx++) outState[idx] = _sBox[inState[idx]];
|
||||
for (int idx = 0; idx <= 15; idx++)
|
||||
{
|
||||
outState[idx] = _sBox[inState[idx]];
|
||||
}
|
||||
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
|
@ -301,7 +313,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
private static void FromByteArrayToVector(byte[] state, ref Vector128<float> op)
|
||||
{
|
||||
if (!Sse2.IsSupported) throw new PlatformNotSupportedException();
|
||||
if (!Sse2.IsSupported)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
op = Sse.StaticCast<byte, float>(Sse2.SetVector128(
|
||||
state[15], state[14], state[13], state[12],
|
||||
|
|
|
@ -36,7 +36,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.EmitCall(mthdInfo);
|
||||
|
||||
if (context.CurrOp.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
if (context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
|
@ -230,7 +233,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.Emit(OpCodes.Xor);
|
||||
|
||||
if (context.CurrOp.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
if (context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
context.Emit(OpCodes.Sub);
|
||||
|
||||
|
@ -308,9 +314,13 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
ASoftFallback.EmitCall(context, name32);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASoftFallback.EmitCall(context, name64);
|
||||
}
|
||||
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
@ -434,7 +444,10 @@ namespace ChocolArm64.Instruction
|
|||
//we need to cast it to a 32-bits integer. This is fine because we
|
||||
//AND the value and only keep the lower 5 or 6 bits anyway -- it
|
||||
//could very well fit on a byte.
|
||||
if (context.CurrOp.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_I4);
|
||||
if (context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_I4);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitZeroCvFlags(AILEmitterCtx context)
|
||||
|
|
|
@ -136,9 +136,13 @@ namespace ChocolArm64.Instruction
|
|||
IAOpCodeAlu op = (IAOpCodeAlu)context.CurrOp;
|
||||
|
||||
if (op.DataOp == ADataOp.Logical || op is IAOpCodeAluRs)
|
||||
{
|
||||
context.EmitLdintzr(op.Rn);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitLdint(op.Rn);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitDataLoadOper2(AILEmitterCtx context)
|
||||
|
@ -184,9 +188,13 @@ namespace ChocolArm64.Instruction
|
|||
IAOpCodeAlu op = (IAOpCodeAlu)context.CurrOp;
|
||||
|
||||
if (setFlags || op is IAOpCodeAluRs)
|
||||
{
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitStint(op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitSetNzcv(AILEmitterCtx context, int nzcv)
|
||||
|
|
|
@ -125,9 +125,13 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLsl(op.GetBitsCount() - width);
|
||||
|
||||
if (signed)
|
||||
{
|
||||
context.EmitAsr(op.Shift - width);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitLsr(op.Shift - width);
|
||||
}
|
||||
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
@ -151,9 +155,11 @@ namespace ChocolArm64.Instruction
|
|||
context.Emit(ilOp);
|
||||
|
||||
if (op.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(signed
|
||||
? OpCodes.Conv_I8
|
||||
: OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
|
|
@ -32,33 +32,49 @@ namespace ChocolArm64.Instruction
|
|||
public static void Crc32Cb(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Crc32(context, typeof(uint), typeof(byte));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32Cb));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Crc32Ch(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Crc32(context, typeof(uint), typeof(ushort));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32Ch));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Crc32Cw(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Crc32(context, typeof(uint), typeof(uint));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32Cw));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Crc32Cx(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Crc32(context, typeof(ulong), typeof(ulong));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32Cx));
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitSse42Crc32(AILEmitterCtx context, Type crc, Type data)
|
||||
|
@ -79,13 +95,19 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
if (op.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_U4);
|
||||
if (op.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
ASoftFallback.EmitCall(context, name);
|
||||
|
||||
if (op.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
if (op.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
|
|
@ -43,16 +43,26 @@ namespace ChocolArm64.Instruction
|
|||
EmitLoadAddress(context);
|
||||
|
||||
if (signed && op.Extend64)
|
||||
{
|
||||
EmitReadSx64Call(context, op.Size);
|
||||
}
|
||||
else if (signed)
|
||||
{
|
||||
EmitReadSx32Call(context, op.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitReadZxCall(context, op.Size);
|
||||
}
|
||||
|
||||
if (op is IAOpCodeSimd)
|
||||
{
|
||||
context.EmitStvec(op.Rt);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitStintzr(op.Rt);
|
||||
}
|
||||
|
||||
EmitWBackIfNeeded(context);
|
||||
}
|
||||
|
@ -61,20 +71,31 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
IAOpCodeLit op = (IAOpCodeLit)context.CurrOp;
|
||||
|
||||
if (op.Prefetch) return;
|
||||
if (op.Prefetch)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdc_I8(op.Imm);
|
||||
|
||||
if (op.Signed)
|
||||
{
|
||||
EmitReadSx64Call(context, op.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitReadZxCall(context, op.Size);
|
||||
}
|
||||
|
||||
if (op is IAOpCodeSimd)
|
||||
{
|
||||
context.EmitStvec(op.Rt);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitStint(op.Rt);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ldp(AILEmitterCtx context)
|
||||
|
@ -84,14 +105,22 @@ namespace ChocolArm64.Instruction
|
|||
void EmitReadAndStore(int rt)
|
||||
{
|
||||
if (op.Extend64)
|
||||
{
|
||||
EmitReadSx64Call(context, op.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitReadZxCall(context, op.Size);
|
||||
}
|
||||
|
||||
if (op is IAOpCodeSimd)
|
||||
{
|
||||
context.EmitStvec(rt);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitStintzr(rt);
|
||||
}
|
||||
}
|
||||
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
|
@ -120,9 +149,13 @@ namespace ChocolArm64.Instruction
|
|||
EmitLoadAddress(context);
|
||||
|
||||
if (op is IAOpCodeSimd)
|
||||
{
|
||||
context.EmitLdvec(op.Rt);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitLdintzr(op.Rt);
|
||||
}
|
||||
|
||||
EmitWriteCall(context, op.Size);
|
||||
|
||||
|
@ -138,9 +171,13 @@ namespace ChocolArm64.Instruction
|
|||
EmitLoadAddress(context);
|
||||
|
||||
if (op is IAOpCodeSimd)
|
||||
{
|
||||
context.EmitLdvec(op.Rt);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitLdintzr(op.Rt);
|
||||
}
|
||||
|
||||
EmitWriteCall(context, op.Size);
|
||||
|
||||
|
@ -151,9 +188,13 @@ namespace ChocolArm64.Instruction
|
|||
context.Emit(OpCodes.Add);
|
||||
|
||||
if (op is IAOpCodeSimd)
|
||||
{
|
||||
context.EmitLdvec(op.Rt2);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitLdintzr(op.Rt2);
|
||||
}
|
||||
|
||||
EmitWriteCall(context, op.Size);
|
||||
|
||||
|
@ -181,7 +222,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdintzr(op.Rm);
|
||||
context.EmitCast(op.IntType);
|
||||
|
||||
if (op.Shift) context.EmitLsl(op.Size);
|
||||
if (op.Shift)
|
||||
{
|
||||
context.EmitLsl(op.Size);
|
||||
}
|
||||
|
||||
context.Emit(OpCodes.Add);
|
||||
break;
|
||||
|
|
|
@ -78,9 +78,15 @@ namespace ChocolArm64.Instruction
|
|||
bool ordered = (accType & AccessType.Ordered) != 0;
|
||||
bool exclusive = (accType & AccessType.Exclusive) != 0;
|
||||
|
||||
if (ordered) EmitBarrier(context);
|
||||
if (ordered)
|
||||
{
|
||||
EmitBarrier(context);
|
||||
}
|
||||
|
||||
if (exclusive) EmitMemoryCall(context, nameof(AMemory.SetExclusive), op.Rn);
|
||||
if (exclusive)
|
||||
{
|
||||
EmitMemoryCall(context, nameof(AMemory.SetExclusive), op.Rn);
|
||||
}
|
||||
|
||||
context.EmitLdint(op.Rn);
|
||||
context.EmitSttmp();
|
||||
|
@ -153,7 +159,10 @@ namespace ChocolArm64.Instruction
|
|||
bool ordered = (accType & AccessType.Ordered) != 0;
|
||||
bool exclusive = (accType & AccessType.Exclusive) != 0;
|
||||
|
||||
if (ordered) EmitBarrier(context);
|
||||
if (ordered)
|
||||
{
|
||||
EmitBarrier(context);
|
||||
}
|
||||
|
||||
AILLabel lblEx = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
@ -209,7 +218,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Core));
|
||||
|
||||
if (rn != -1) context.EmitLdint(rn);
|
||||
if (rn != -1)
|
||||
{
|
||||
context.EmitLdint(rn);
|
||||
}
|
||||
|
||||
context.EmitCall(typeof(AMemory), name);
|
||||
}
|
||||
|
|
|
@ -36,9 +36,13 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
string name = null;
|
||||
|
||||
if (size < 0 || size > (isSimd ? 4 : 3)) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
if (size < 0 || size > (isSimd ? 4 : 3))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
if (isSimd)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 0: name = nameof(AMemory.ReadVector8); break;
|
||||
|
@ -47,7 +51,9 @@ namespace ChocolArm64.Instruction
|
|||
case 3: name = nameof(AMemory.ReadVector64); break;
|
||||
case 4: name = nameof(AMemory.ReadVector128); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 0: name = nameof(AMemory.ReadByte); break;
|
||||
|
@ -55,6 +61,7 @@ namespace ChocolArm64.Instruction
|
|||
case 2: name = nameof(AMemory.ReadUInt32); break;
|
||||
case 3: name = nameof(AMemory.ReadUInt64); break;
|
||||
}
|
||||
}
|
||||
|
||||
context.EmitCall(typeof(AMemory), name);
|
||||
|
||||
|
@ -62,17 +69,21 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (ext == Extension.Sx32 ||
|
||||
ext == Extension.Sx64)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 0: context.Emit(OpCodes.Conv_I1); break;
|
||||
case 1: context.Emit(OpCodes.Conv_I2); break;
|
||||
case 2: context.Emit(OpCodes.Conv_I4); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (size < 3)
|
||||
{
|
||||
context.Emit(ext == Extension.Sx64
|
||||
? OpCodes.Conv_I8
|
||||
: OpCodes.Conv_U8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,11 +93,18 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
string name = null;
|
||||
|
||||
if (size < 0 || size > (isSimd ? 4 : 3)) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
if (size < 0 || size > (isSimd ? 4 : 3))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
if (size < 3 && !isSimd) context.Emit(OpCodes.Conv_I4);
|
||||
if (size < 3 && !isSimd)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_I4);
|
||||
}
|
||||
|
||||
if (isSimd)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 0: name = nameof(AMemory.WriteVector8); break;
|
||||
|
@ -95,7 +113,9 @@ namespace ChocolArm64.Instruction
|
|||
case 3: name = nameof(AMemory.WriteVector64); break;
|
||||
case 4: name = nameof(AMemory.WriteVector128); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 0: name = nameof(AMemory.WriteByte); break;
|
||||
|
@ -103,6 +123,7 @@ namespace ChocolArm64.Instruction
|
|||
case 2: name = nameof(AMemory.WriteUInt32); break;
|
||||
case 3: name = nameof(AMemory.WriteUInt64); break;
|
||||
}
|
||||
}
|
||||
|
||||
context.EmitCall(typeof(AMemory), name);
|
||||
}
|
||||
|
|
|
@ -33,9 +33,13 @@ namespace ChocolArm64.Instruction
|
|||
public static void Add_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(context, nameof(Sse2.Add));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Add));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Addhn_V(AILEmitterCtx context)
|
||||
|
@ -99,7 +103,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Clz_V(AILEmitterCtx context)
|
||||
|
@ -133,7 +140,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Cnt_V(AILEmitterCtx context)
|
||||
|
@ -147,14 +157,21 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorExtractZx(context, op.Rn, index, 0);
|
||||
|
||||
if (Popcnt.IsSupported)
|
||||
{
|
||||
context.EmitCall(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { typeof(ulong) }));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.CountSetBits8));
|
||||
}
|
||||
|
||||
EmitVectorInsert(context, op.Rd, index, 0);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fabd_S(AILEmitterCtx context)
|
||||
|
@ -187,24 +204,32 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.AddScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpAdd));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fadd_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.Add));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpAdd));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Faddp_S(AILEmitterCtx context)
|
||||
|
@ -230,24 +255,32 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.DivideScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpDiv));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fdiv_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.Divide));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpDiv));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fmadd_S(AILEmitterCtx context)
|
||||
|
@ -300,24 +333,32 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.MaxScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpMax));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fmax_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.Max));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpMax));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fmaxnm_S(AILEmitterCtx context)
|
||||
|
@ -348,24 +389,32 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.MinScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpMin));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fmin_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.Min));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpMin));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fminnm_S(AILEmitterCtx context)
|
||||
|
@ -496,12 +545,16 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.MultiplyScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpMul));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fmul_Se(AILEmitterCtx context)
|
||||
|
@ -513,12 +566,16 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.Multiply));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpMul));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fmul_Ve(AILEmitterCtx context)
|
||||
|
@ -710,7 +767,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
|
@ -774,11 +834,17 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
if (op.Size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.RoundF));
|
||||
}
|
||||
else if (op.Size == 1)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.Round));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -793,11 +859,17 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
if (sizeF == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.RoundF));
|
||||
}
|
||||
else if (sizeF == 1)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.Round));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -861,11 +933,17 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
if (op.Size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.RoundF));
|
||||
}
|
||||
else if (op.Size == 1)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.Round));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -878,11 +956,17 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
if (op.Size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.RoundF));
|
||||
}
|
||||
else if (op.Size == 1)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.Round));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -992,7 +1076,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
|
@ -1028,48 +1115,64 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.SqrtScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarUnaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpSqrt));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fsqrt_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.Sqrt));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorUnaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpSqrt));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fsub_S(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.SubtractScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpSub));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fsub_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.FastFp && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.Subtract));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpF(context, () =>
|
||||
{
|
||||
EmitSoftFloatCall(context, nameof(ASoftFloat_32.FpSub));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Mla_V(AILEmitterCtx context)
|
||||
|
@ -1267,7 +1370,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithSignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1314,7 +1420,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithSignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1582,7 +1691,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithSignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1653,9 +1765,13 @@ namespace ChocolArm64.Instruction
|
|||
public static void Sub_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(context, nameof(Sse2.Subtract));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Sub));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Subhn_V(AILEmitterCtx context)
|
||||
|
@ -1821,7 +1937,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1854,7 +1973,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2056,7 +2178,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2171,7 +2296,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitDoublingMultiplyHighHalf(AILEmitterCtx context, bool round)
|
||||
|
@ -2250,7 +2378,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (part == 0) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,11 +22,17 @@ namespace ChocolArm64.Instruction
|
|||
if (context.CurrOp is AOpCodeSimdReg op)
|
||||
{
|
||||
if (op.Size < 3 && AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(context, nameof(Sse2.CompareEqual));
|
||||
}
|
||||
else if (op.Size == 3 && AOptimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Op(context, nameof(Sse41.CompareEqual));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCmp(context, OpCodes.Beq_S, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -54,11 +60,17 @@ namespace ChocolArm64.Instruction
|
|||
if (context.CurrOp is AOpCodeSimdReg op)
|
||||
{
|
||||
if (op.Size < 3 && AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(context, nameof(Sse2.CompareGreaterThan));
|
||||
}
|
||||
else if (op.Size == 3 && AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Op(context, nameof(Sse42.CompareGreaterThan));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCmp(context, OpCodes.Bgt_S, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -145,54 +157,78 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.CompareEqualScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarFcmp(context, OpCodes.Beq_S);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcmeq_V(AILEmitterCtx context)
|
||||
{
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.CompareEqual));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorFcmp(context, OpCodes.Beq_S);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcmge_S(AILEmitterCtx context)
|
||||
{
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqualScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarFcmp(context, OpCodes.Bge_S);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcmge_V(AILEmitterCtx context)
|
||||
{
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqual));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorFcmp(context, OpCodes.Bge_S);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcmgt_S(AILEmitterCtx context)
|
||||
{
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarFcmp(context, OpCodes.Bgt_S);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcmgt_V(AILEmitterCtx context)
|
||||
{
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.CompareGreaterThan));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorFcmp(context, OpCodes.Bgt_S);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcmle_S(AILEmitterCtx context)
|
||||
|
@ -247,9 +283,13 @@ namespace ChocolArm64.Instruction
|
|||
if (cmpWithZero)
|
||||
{
|
||||
if (op.Size == 0)
|
||||
{
|
||||
context.EmitLdc_R4(0f);
|
||||
}
|
||||
else /* if (Op.Size == 1) */
|
||||
{
|
||||
context.EmitLdc_R8(0d);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -306,11 +346,17 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorExtractF(context, reg, 0, op.Size);
|
||||
|
||||
if (op.Size == 0)
|
||||
{
|
||||
context.EmitCall(typeof(float), nameof(float.IsNaN));
|
||||
}
|
||||
else if (op.Size == 1)
|
||||
{
|
||||
context.EmitCall(typeof(double), nameof(double.IsNaN));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitCmp(AILEmitterCtx context, OpCode ilOp, bool scalar)
|
||||
|
@ -327,9 +373,13 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorExtractSx(context, op.Rn, index, op.Size);
|
||||
|
||||
if (op is AOpCodeSimdReg binOp)
|
||||
{
|
||||
EmitVectorExtractSx(context, binOp.Rm, index, op.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitLdc_I8(0L);
|
||||
}
|
||||
|
||||
AILLabel lblTrue = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
@ -347,7 +397,10 @@ namespace ChocolArm64.Instruction
|
|||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitCmtst(AILEmitterCtx context, bool scalar)
|
||||
|
@ -384,7 +437,10 @@ namespace ChocolArm64.Instruction
|
|||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitScalarFcmp(AILEmitterCtx context, OpCode ilOp)
|
||||
|
@ -401,9 +457,15 @@ namespace ChocolArm64.Instruction
|
|||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = bytes >> (sizeF + 2);
|
||||
|
||||
for (int index = 0; index < elems; index++) EmitFcmp(context, ilOp, index, false);
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitFcmp(context, ilOp, index, false);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFcmp(AILEmitterCtx context, OpCode ilOp, int index, bool scalar)
|
||||
|
@ -417,11 +479,17 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorExtractF(context, op.Rn, index, sizeF);
|
||||
|
||||
if (op is AOpCodeSimdReg binOp)
|
||||
{
|
||||
EmitVectorExtractF(context, binOp.Rm, index, sizeF);
|
||||
}
|
||||
else if (sizeF == 0)
|
||||
{
|
||||
context.EmitLdc_R4(0f);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
context.EmitLdc_R8(0d);
|
||||
}
|
||||
|
||||
AILLabel lblTrue = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
@ -429,9 +497,13 @@ namespace ChocolArm64.Instruction
|
|||
context.Emit(ilOp, lblTrue);
|
||||
|
||||
if (scalar)
|
||||
{
|
||||
EmitVectorZeroAll(context, op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorInsert(context, op.Rd, index, sizeF + 2, 0);
|
||||
}
|
||||
|
||||
context.Emit(OpCodes.Br_S, lblEnd);
|
||||
|
||||
|
|
|
@ -155,7 +155,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (part == 0) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcvtns_S(AILEmitterCtx context)
|
||||
|
@ -234,7 +237,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32) context.Emit(OpCodes.Conv_U4);
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
|
||||
EmitFloatCast(context, op.Size);
|
||||
|
||||
|
@ -263,7 +269,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32) context.Emit(OpCodes.Conv_U4);
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
|
||||
context.Emit(OpCodes.Conv_R_Un);
|
||||
|
||||
|
@ -292,7 +301,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
private static int GetFBits(AILEmitterCtx context)
|
||||
{
|
||||
if (context.CurrOp is AOpCodeSimdShImm op) return GetImmShr(op);
|
||||
if (context.CurrOp is AOpCodeSimdShImm op)
|
||||
{
|
||||
return GetImmShr(op);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -300,11 +312,17 @@ namespace ChocolArm64.Instruction
|
|||
private static void EmitFloatCast(AILEmitterCtx context, int size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_R4);
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_R8);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFcvtn(AILEmitterCtx context, bool signed, bool scalar)
|
||||
|
@ -317,7 +335,10 @@ namespace ChocolArm64.Instruction
|
|||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = !scalar ? bytes >> sizeI : 1;
|
||||
|
||||
if (scalar && sizeF == 0) EmitVectorZeroLowerTmp(context);
|
||||
if (scalar && sizeF == 0)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(context);
|
||||
}
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
|
@ -346,7 +367,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFcvt_s_Gp(AILEmitterCtx context, Action emit)
|
||||
|
@ -368,11 +392,18 @@ namespace ChocolArm64.Instruction
|
|||
emit();
|
||||
|
||||
if (signed)
|
||||
{
|
||||
EmitScalarFcvts(context, op.Size, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarFcvtu(context, op.Size, 0);
|
||||
}
|
||||
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
@ -394,11 +425,18 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorExtractF(context, op.Rn, 0, op.Size);
|
||||
|
||||
if (signed)
|
||||
{
|
||||
EmitScalarFcvts(context, op.Size, op.FBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitScalarFcvtu(context, op.Size, op.FBits);
|
||||
}
|
||||
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
@ -429,7 +467,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
EmitVectorExtract(context, op.Rn, index, sizeI, signed);
|
||||
|
||||
if (!signed) context.Emit(OpCodes.Conv_R_Un);
|
||||
if (!signed)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_R_Un);
|
||||
}
|
||||
|
||||
context.Emit(sizeF == 0
|
||||
? OpCodes.Conv_R4
|
||||
|
@ -440,7 +481,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsertF(context, op.Rd, index, sizeF);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitScalarFcvtzs(AILEmitterCtx context)
|
||||
|
@ -467,15 +511,22 @@ namespace ChocolArm64.Instruction
|
|||
EmitF2iFBitsMul(context, sizeF, fBits);
|
||||
|
||||
if (sizeF == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF32ToS32)
|
||||
: nameof(AVectorHelper.SatF32ToU32));
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF64ToS64)
|
||||
: nameof(AVectorHelper.SatF64ToU64));
|
||||
}
|
||||
|
||||
if (sizeF == 0) context.Emit(OpCodes.Conv_U8);
|
||||
if (sizeF == 0)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
EmitScalarSet(context, op.Rd, sizeI);
|
||||
}
|
||||
|
@ -509,63 +560,95 @@ namespace ChocolArm64.Instruction
|
|||
EmitF2iFBitsMul(context, sizeF, fBits);
|
||||
|
||||
if (sizeF == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF32ToS32)
|
||||
: nameof(AVectorHelper.SatF32ToU32));
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF64ToS64)
|
||||
: nameof(AVectorHelper.SatF64ToU64));
|
||||
}
|
||||
|
||||
if (sizeF == 0) context.Emit(OpCodes.Conv_U8);
|
||||
if (sizeF == 0)
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
EmitVectorInsert(context, op.Rd, index, sizeI);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitScalarFcvts(AILEmitterCtx context, int size, int fBits)
|
||||
{
|
||||
if (size < 0 || size > 1) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
if (size < 0 || size > 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
EmitF2iFBitsMul(context, size, fBits);
|
||||
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF32ToS32));
|
||||
}
|
||||
else /* if (Size == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF64ToS32));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF32ToS64));
|
||||
}
|
||||
else /* if (Size == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF64ToS64));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitScalarFcvtu(AILEmitterCtx context, int size, int fBits)
|
||||
{
|
||||
if (size < 0 || size > 1) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
if (size < 0 || size > 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
EmitF2iFBitsMul(context, size, fBits);
|
||||
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF32ToU32));
|
||||
}
|
||||
else /* if (Size == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF64ToU32));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF32ToU64));
|
||||
}
|
||||
else /* if (Size == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF64ToU64));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,11 +657,17 @@ namespace ChocolArm64.Instruction
|
|||
if (fBits != 0)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
context.EmitLdc_R4(MathF.Pow(2f, fBits));
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
context.EmitLdc_R8(Math.Pow(2d, fBits));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
context.Emit(OpCodes.Mul);
|
||||
}
|
||||
|
@ -589,11 +678,17 @@ namespace ChocolArm64.Instruction
|
|||
if (fBits != 0)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
context.EmitLdc_R4(1f / MathF.Pow(2f, fBits));
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
context.EmitLdc_R8(1d / Math.Pow(2d, fBits));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
context.Emit(OpCodes.Mul);
|
||||
}
|
||||
|
|
|
@ -103,7 +103,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithSignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitLdvecWithSignedCast(AILEmitterCtx context, int reg, int size)
|
||||
|
@ -200,7 +203,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
context.EmitLdvec(reg);
|
||||
|
||||
if (sizeF == 1) AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorSingleToDouble));
|
||||
if (sizeF == 1)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorSingleToDouble));
|
||||
}
|
||||
}
|
||||
|
||||
Ldvec(op.Rn);
|
||||
|
@ -230,16 +236,23 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitCall(type.GetMethod(name, new Type[] { baseType }));
|
||||
}
|
||||
|
||||
if (sizeF == 1) AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorDoubleToSingle));
|
||||
if (sizeF == 1)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorDoubleToSingle));
|
||||
}
|
||||
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (scalar)
|
||||
{
|
||||
if (sizeF == 0)
|
||||
{
|
||||
EmitVectorZero32_128(context, op.Rd);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
|
@ -256,9 +269,13 @@ namespace ChocolArm64.Instruction
|
|||
MethodInfo mthdInfo;
|
||||
|
||||
if (sizeF == 0)
|
||||
{
|
||||
mthdInfo = typeof(MathF).GetMethod(name, new Type[] { typeof(float) });
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
mthdInfo = typeof(Math).GetMethod(name, new Type[] { typeof(double) });
|
||||
}
|
||||
|
||||
context.EmitCall(mthdInfo);
|
||||
}
|
||||
|
@ -272,9 +289,13 @@ namespace ChocolArm64.Instruction
|
|||
MethodInfo mthdInfo;
|
||||
|
||||
if (sizeF == 0)
|
||||
{
|
||||
mthdInfo = typeof(MathF).GetMethod(name, new Type[] { typeof(float), typeof(float) });
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
mthdInfo = typeof(Math).GetMethod(name, new Type[] { typeof(double), typeof(double) });
|
||||
}
|
||||
|
||||
context.EmitCall(mthdInfo);
|
||||
}
|
||||
|
@ -288,9 +309,13 @@ namespace ChocolArm64.Instruction
|
|||
MethodInfo mthdInfo;
|
||||
|
||||
if (sizeF == 0)
|
||||
{
|
||||
mthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), new Type[] { typeof(float), typeof(MidpointRounding) });
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
mthdInfo = typeof(Math).GetMethod(nameof(Math.Round), new Type[] { typeof(double), typeof(MidpointRounding) });
|
||||
}
|
||||
|
||||
context.EmitLdc_I4((int)roundMode);
|
||||
|
||||
|
@ -306,9 +331,13 @@ namespace ChocolArm64.Instruction
|
|||
MethodInfo mthdInfo;
|
||||
|
||||
if (sizeF == 0)
|
||||
{
|
||||
mthdInfo = typeof(ASoftFloat).GetMethod(name, new Type[] { typeof(float) });
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
mthdInfo = typeof(ASoftFloat).GetMethod(name, new Type[] { typeof(double) });
|
||||
}
|
||||
|
||||
context.EmitCall(mthdInfo);
|
||||
}
|
||||
|
@ -346,7 +375,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
if (ternary) EmitVectorExtractF(context, op.Rd, 0, sizeF);
|
||||
if (ternary)
|
||||
{
|
||||
EmitVectorExtractF(context, op.Rd, 0, sizeF);
|
||||
}
|
||||
|
||||
EmitVectorExtractF(context, op.Rn, 0, sizeF);
|
||||
EmitVectorExtractF(context, op.Rm, elem, sizeF);
|
||||
|
@ -389,11 +421,20 @@ namespace ChocolArm64.Instruction
|
|||
bool rn = (opers & OperFlags.Rn) != 0;
|
||||
bool rm = (opers & OperFlags.Rm) != 0;
|
||||
|
||||
if (rd) EmitVectorExtract(context, op.Rd, 0, op.Size, signed);
|
||||
if (rd)
|
||||
{
|
||||
EmitVectorExtract(context, op.Rd, 0, op.Size, signed);
|
||||
}
|
||||
|
||||
if (rn) EmitVectorExtract(context, op.Rn, 0, op.Size, signed);
|
||||
if (rn)
|
||||
{
|
||||
EmitVectorExtract(context, op.Rn, 0, op.Size, signed);
|
||||
}
|
||||
|
||||
if (rm) EmitVectorExtract(context, ((AOpCodeSimdReg)op).Rm, 0, op.Size, signed);
|
||||
if (rm)
|
||||
{
|
||||
EmitVectorExtract(context, ((AOpCodeSimdReg)op).Rm, 0, op.Size, signed);
|
||||
}
|
||||
|
||||
emit();
|
||||
|
||||
|
@ -425,11 +466,20 @@ namespace ChocolArm64.Instruction
|
|||
bool rn = (opers & OperFlags.Rn) != 0;
|
||||
bool rm = (opers & OperFlags.Rm) != 0;
|
||||
|
||||
if (ra) EmitVectorExtractF(context, ((AOpCodeSimdReg)op).Ra, 0, sizeF);
|
||||
if (ra)
|
||||
{
|
||||
EmitVectorExtractF(context, ((AOpCodeSimdReg)op).Ra, 0, sizeF);
|
||||
}
|
||||
|
||||
if (rn) EmitVectorExtractF(context, op.Rn, 0, sizeF);
|
||||
if (rn)
|
||||
{
|
||||
EmitVectorExtractF(context, op.Rn, 0, sizeF);
|
||||
}
|
||||
|
||||
if (rm) EmitVectorExtractF(context, ((AOpCodeSimdReg)op).Rm, 0, sizeF);
|
||||
if (rm)
|
||||
{
|
||||
EmitVectorExtractF(context, ((AOpCodeSimdReg)op).Rm, 0, sizeF);
|
||||
}
|
||||
|
||||
emit();
|
||||
|
||||
|
@ -466,18 +516,30 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
if (rd) EmitVectorExtractF(context, op.Rd, index, sizeF);
|
||||
if (rd)
|
||||
{
|
||||
EmitVectorExtractF(context, op.Rd, index, sizeF);
|
||||
}
|
||||
|
||||
if (rn) EmitVectorExtractF(context, op.Rn, index, sizeF);
|
||||
if (rn)
|
||||
{
|
||||
EmitVectorExtractF(context, op.Rn, index, sizeF);
|
||||
}
|
||||
|
||||
if (rm) EmitVectorExtractF(context, ((AOpCodeSimdReg)op).Rm, index, sizeF);
|
||||
if (rm)
|
||||
{
|
||||
EmitVectorExtractF(context, ((AOpCodeSimdReg)op).Rm, index, sizeF);
|
||||
}
|
||||
|
||||
emit();
|
||||
|
||||
EmitVectorInsertF(context, op.Rd, index, sizeF);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpByElemF(AILEmitterCtx context, Action emit)
|
||||
|
@ -505,7 +567,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
if (ternary) EmitVectorExtractF(context, op.Rd, index, sizeF);
|
||||
if (ternary)
|
||||
{
|
||||
EmitVectorExtractF(context, op.Rd, index, sizeF);
|
||||
}
|
||||
|
||||
EmitVectorExtractF(context, op.Rn, index, sizeF);
|
||||
EmitVectorExtractF(context, op.Rm, elem, sizeF);
|
||||
|
@ -518,7 +583,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorUnaryOpSx(AILEmitterCtx context, Action emit)
|
||||
|
@ -564,18 +632,30 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
if (rd) EmitVectorExtract(context, op.Rd, index, op.Size, signed);
|
||||
if (rd)
|
||||
{
|
||||
EmitVectorExtract(context, op.Rd, index, op.Size, signed);
|
||||
}
|
||||
|
||||
if (rn) EmitVectorExtract(context, op.Rn, index, op.Size, signed);
|
||||
if (rn)
|
||||
{
|
||||
EmitVectorExtract(context, op.Rn, index, op.Size, signed);
|
||||
}
|
||||
|
||||
if (rm) EmitVectorExtract(context, ((AOpCodeSimdReg)op).Rm, index, op.Size, signed);
|
||||
if (rm)
|
||||
{
|
||||
EmitVectorExtract(context, ((AOpCodeSimdReg)op).Rm, index, op.Size, signed);
|
||||
}
|
||||
|
||||
emit();
|
||||
|
||||
EmitVectorInsert(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorBinaryOpByElemSx(AILEmitterCtx context, Action emit)
|
||||
|
@ -611,7 +691,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
if (ternary) EmitVectorExtract(context, op.Rd, index, op.Size, signed);
|
||||
if (ternary)
|
||||
{
|
||||
EmitVectorExtract(context, op.Rd, index, op.Size, signed);
|
||||
}
|
||||
|
||||
EmitVectorExtract(context, op.Rn, index, op.Size, signed);
|
||||
context.EmitLdtmp();
|
||||
|
@ -624,7 +707,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorImmUnaryOp(AILEmitterCtx context, Action emit)
|
||||
|
@ -646,7 +732,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
if (binary) EmitVectorExtractZx(context, op.Rd, index, op.Size);
|
||||
if (binary)
|
||||
{
|
||||
EmitVectorExtractZx(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
context.EmitLdc_I8(op.Imm);
|
||||
|
||||
|
@ -655,7 +744,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorWidenRmBinaryOpSx(AILEmitterCtx context, Action emit)
|
||||
|
@ -720,7 +812,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
if (ternary) EmitVectorExtract(context, op.Rd, index, op.Size + 1, signed);
|
||||
if (ternary)
|
||||
{
|
||||
EmitVectorExtract(context, op.Rd, index, op.Size + 1, signed);
|
||||
}
|
||||
|
||||
EmitVectorExtract(context, op.Rn, part + index, op.Size, signed);
|
||||
EmitVectorExtract(context, op.Rm, part + index, op.Size, signed);
|
||||
|
@ -772,7 +867,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorPairwiseOpF(AILEmitterCtx context, Action emit)
|
||||
|
@ -805,7 +903,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
@ -845,7 +946,10 @@ namespace ChocolArm64.Instruction
|
|||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = !scalar ? bytes >> op.Size : 1;
|
||||
|
||||
if (scalar) EmitVectorZeroLowerTmp(context);
|
||||
if (scalar)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(context);
|
||||
}
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
|
@ -854,9 +958,13 @@ namespace ChocolArm64.Instruction
|
|||
emit();
|
||||
|
||||
if (op.Size <= 2)
|
||||
{
|
||||
EmitSatQ(context, op.Size, true, true);
|
||||
}
|
||||
else /* if (Op.Size == 3) */
|
||||
{
|
||||
EmitUnarySignedSatQAbsOrNeg(context);
|
||||
}
|
||||
|
||||
EmitVectorInsertTmp(context, index, op.Size);
|
||||
}
|
||||
|
@ -864,7 +972,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitScalarSaturatingBinaryOpSx(AILEmitterCtx context, SaturatingFlags flags)
|
||||
|
@ -902,9 +1013,13 @@ namespace ChocolArm64.Instruction
|
|||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = !scalar ? bytes >> op.Size : 1;
|
||||
|
||||
if (scalar) EmitVectorZeroLowerTmp(context);
|
||||
if (scalar)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(context);
|
||||
}
|
||||
|
||||
if (add || sub)
|
||||
{
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorExtract(context, op.Rn, index, op.Size, signed);
|
||||
|
@ -919,14 +1034,20 @@ namespace ChocolArm64.Instruction
|
|||
else /* if (Op.Size == 3) */
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
EmitBinarySatQAdd(context, signed);
|
||||
}
|
||||
else /* if (Sub) */
|
||||
{
|
||||
EmitBinarySatQSub(context, signed);
|
||||
}
|
||||
}
|
||||
|
||||
EmitVectorInsertTmp(context, index, op.Size);
|
||||
}
|
||||
}
|
||||
else if (accumulate)
|
||||
{
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorExtract(context, op.Rn, index, op.Size, !signed);
|
||||
|
@ -945,7 +1066,9 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitVectorInsertTmp(context, index, op.Size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorExtract(context, op.Rn, index, op.Size, signed);
|
||||
|
@ -957,11 +1080,15 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitVectorInsertTmp(context, index, op.Size);
|
||||
}
|
||||
}
|
||||
|
||||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
@ -992,7 +1119,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
int part = !scalar && op.RegisterSize == ARegisterSize.Simd128 ? elems : 0;
|
||||
|
||||
if (scalar) EmitVectorZeroLowerTmp(context);
|
||||
if (scalar)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(context);
|
||||
}
|
||||
|
||||
if (part != 0)
|
||||
{
|
||||
|
@ -1012,7 +1142,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (part == 0) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
// TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned).
|
||||
|
@ -1022,25 +1155,35 @@ namespace ChocolArm64.Instruction
|
|||
bool signedSrc,
|
||||
bool signedDst)
|
||||
{
|
||||
if (sizeDst > 2) throw new ArgumentOutOfRangeException(nameof(sizeDst));
|
||||
if (sizeDst > 2)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(sizeDst));
|
||||
}
|
||||
|
||||
context.EmitLdc_I4(sizeDst);
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
if (signedSrc)
|
||||
{
|
||||
ASoftFallback.EmitCall(context, signedDst
|
||||
? nameof(ASoftFallback.SignedSrcSignedDstSatQ)
|
||||
: nameof(ASoftFallback.SignedSrcUnsignedDstSatQ));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASoftFallback.EmitCall(context, signedDst
|
||||
? nameof(ASoftFallback.UnsignedSrcSignedDstSatQ)
|
||||
: nameof(ASoftFallback.UnsignedSrcUnsignedDstSatQ));
|
||||
}
|
||||
}
|
||||
|
||||
// TSrc (64bit) == TDst (64bit); signed.
|
||||
public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx context)
|
||||
{
|
||||
if (((AOpCodeSimd)context.CurrOp).Size < 3) throw new InvalidOperationException();
|
||||
if (((AOpCodeSimd)context.CurrOp).Size < 3)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
|
@ -1050,7 +1193,10 @@ namespace ChocolArm64.Instruction
|
|||
// TSrcs (64bit) == TDst (64bit); signed, unsigned.
|
||||
public static void EmitBinarySatQAdd(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
if (((AOpCodeSimdReg)context.CurrOp).Size < 3) throw new InvalidOperationException();
|
||||
if (((AOpCodeSimdReg)context.CurrOp).Size < 3)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
|
@ -1062,7 +1208,10 @@ namespace ChocolArm64.Instruction
|
|||
// TSrcs (64bit) == TDst (64bit); signed, unsigned.
|
||||
public static void EmitBinarySatQSub(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
if (((AOpCodeSimdReg)context.CurrOp).Size < 3) throw new InvalidOperationException();
|
||||
if (((AOpCodeSimdReg)context.CurrOp).Size < 3)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
|
@ -1074,7 +1223,10 @@ namespace ChocolArm64.Instruction
|
|||
// TSrcs (64bit) == TDst (64bit); signed, unsigned.
|
||||
public static void EmitBinarySatQAccumulate(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
if (((AOpCodeSimd)context.CurrOp).Size < 3) throw new InvalidOperationException();
|
||||
if (((AOpCodeSimd)context.CurrOp).Size < 3)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
|
@ -1139,11 +1291,17 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdc_I4(index);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorExtractSingle));
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorExtractDouble));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorZeroAll(AILEmitterCtx context, int rd)
|
||||
|
@ -1270,11 +1428,17 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdc_I4(index);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorInsertSingle));
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorInsertDouble));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
context.EmitStvec(reg);
|
||||
}
|
||||
|
@ -1287,27 +1451,45 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdc_I4(index);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorInsertSingle));
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorInsertDouble));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
context.EmitStvectmp();
|
||||
}
|
||||
|
||||
private static void ThrowIfInvalid(int index, int size)
|
||||
{
|
||||
if ((uint)size > 3u) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
if ((uint)size > 3u)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
if ((uint)index >= 16u >> size) throw new ArgumentOutOfRangeException(nameof(index));
|
||||
if ((uint)index >= 16u >> size)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ThrowIfInvalidF(int index, int size)
|
||||
{
|
||||
if ((uint)size > 1u) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
if ((uint)size > 1u)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
if ((uint)index >= 4u >> size) throw new ArgumentOutOfRangeException(nameof(index));
|
||||
if ((uint)index >= 4u >> size)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,13 @@ namespace ChocolArm64.Instruction
|
|||
public static void And_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(context, nameof(Sse2.And));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.And));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Bic_V(AILEmitterCtx context)
|
||||
|
@ -38,7 +42,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -97,7 +104,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -113,7 +123,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitVectorExtractZx(context, op.Rm, index, op.Size);
|
||||
|
||||
if (notRm) context.Emit(OpCodes.Not);
|
||||
if (notRm)
|
||||
{
|
||||
context.Emit(OpCodes.Not);
|
||||
}
|
||||
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
|
@ -124,7 +137,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,7 +171,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -177,9 +196,13 @@ namespace ChocolArm64.Instruction
|
|||
public static void Eor_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(context, nameof(Sse2.Xor));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Xor));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Not_V(AILEmitterCtx context)
|
||||
|
@ -199,9 +222,13 @@ namespace ChocolArm64.Instruction
|
|||
public static void Orr_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(context, nameof(Sse2.Or));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Or));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Orr_Vi(AILEmitterCtx context)
|
||||
|
@ -228,7 +255,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, op.Rd, index, 0);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Rev16_V(AILEmitterCtx context)
|
||||
|
@ -250,7 +280,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
if (op.Size >= containerSize) throw new InvalidOperationException();
|
||||
if (op.Size >= containerSize)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = bytes >> op.Size;
|
||||
|
@ -269,7 +302,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,8 +38,10 @@ namespace ChocolArm64.Instruction
|
|||
int offset = 0;
|
||||
|
||||
for (int rep = 0; rep < op.Reps; rep++)
|
||||
for (int elem = 0; elem < op.Elems; elem++)
|
||||
for (int sElem = 0; sElem < op.SElems; sElem++)
|
||||
{
|
||||
for (int elem = 0; elem < op.Elems; elem++)
|
||||
{
|
||||
for (int sElem = 0; sElem < op.SElems; sElem++)
|
||||
{
|
||||
int rtt = (op.Rt + rep + sElem) & 0x1f;
|
||||
|
||||
|
@ -55,8 +57,11 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitVectorInsert(context, rtt, elem, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 && elem == op.Elems - 1) EmitVectorZeroUpper(context, rtt);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 && elem == op.Elems - 1)
|
||||
{
|
||||
EmitVectorZeroUpper(context, rtt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
|
@ -72,8 +77,13 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
offset += 1 << op.Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (op.WBack) EmitSimdMemWBack(context, offset);
|
||||
if (op.WBack)
|
||||
{
|
||||
EmitSimdMemWBack(context, offset);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitSimdMemSs(AILEmitterCtx context, bool isLoad)
|
||||
|
@ -94,7 +104,10 @@ namespace ChocolArm64.Instruction
|
|||
if (op.Replicate)
|
||||
{
|
||||
//Only loads uses the replicate mode.
|
||||
if (!isLoad) throw new InvalidOperationException();
|
||||
if (!isLoad)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = bytes >> op.Size;
|
||||
|
@ -112,7 +125,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, rt, index, op.Size);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, rt);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, rt);
|
||||
}
|
||||
|
||||
offset += 1 << op.Size;
|
||||
}
|
||||
|
@ -144,7 +160,10 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
if (op.WBack) EmitSimdMemWBack(context, offset);
|
||||
if (op.WBack)
|
||||
{
|
||||
EmitSimdMemWBack(context, offset);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitSimdMemWBack(AILEmitterCtx context, int offset)
|
||||
|
@ -154,9 +173,13 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdint(op.Rn);
|
||||
|
||||
if (op.Rm != AThreadState.ZrIndex)
|
||||
{
|
||||
context.EmitLdint(op.Rm);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitLdc_I8(offset);
|
||||
}
|
||||
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
|
|
|
@ -32,7 +32,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -46,7 +49,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,7 +79,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ext_V(AILEmitterCtx context)
|
||||
|
@ -91,7 +100,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
int reg = op.Imm4 + index < bytes ? op.Rn : op.Rm;
|
||||
|
||||
if (position == bytes) position = 0;
|
||||
if (position == bytes)
|
||||
{
|
||||
position = 0;
|
||||
}
|
||||
|
||||
EmitVectorExtractZx(context, reg, position++, 0);
|
||||
EmitVectorInsertTmp(context, index, 0);
|
||||
|
@ -100,7 +112,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcsel_S(AILEmitterCtx context)
|
||||
|
@ -200,7 +215,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, op.Rd, index, op.Size + 2);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ins_Gp(AILEmitterCtx context)
|
||||
|
@ -248,7 +266,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.EmitLdvec(op.Rm);
|
||||
|
||||
for (int index = 0; index < op.Size; index++) context.EmitLdvec((op.Rn + index) & 0x1f);
|
||||
for (int index = 0; index < op.Size; index++)
|
||||
{
|
||||
context.EmitLdvec((op.Rn + index) & 0x1f);
|
||||
}
|
||||
|
||||
switch (op.Size)
|
||||
{
|
||||
|
@ -324,7 +345,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
//For XTN, first operand is source, second operand is 0.
|
||||
//For XTN2, first operand is 0, second operand is source.
|
||||
if (part != 0) EmitZeroVector();
|
||||
if (part != 0)
|
||||
{
|
||||
EmitZeroVector();
|
||||
}
|
||||
|
||||
EmitLdvecWithSignedCast(context, op.Rn, op.Size + 1);
|
||||
|
||||
|
@ -345,7 +369,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), wideTypes));
|
||||
|
||||
if (part == 0) EmitZeroVector();
|
||||
if (part == 0)
|
||||
{
|
||||
EmitZeroVector();
|
||||
}
|
||||
|
||||
//Pack values with signed saturation, the signed saturation shouldn't
|
||||
//saturate anything since the upper bits were masked off.
|
||||
|
@ -386,7 +413,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (part == 0) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,7 +461,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorUnzip(AILEmitterCtx context, int part)
|
||||
|
@ -455,7 +488,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorZip(AILEmitterCtx context, int part)
|
||||
|
@ -490,7 +526,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 && part == 0) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 && part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -513,7 +552,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -101,7 +104,10 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsert(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sqrshrn_S(AILEmitterCtx context)
|
||||
|
@ -182,7 +188,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithSignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -230,7 +239,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithSignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -271,7 +283,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithSignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -304,7 +319,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithSignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -369,7 +387,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -416,7 +437,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -456,7 +480,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -488,7 +515,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -550,9 +580,13 @@ namespace ChocolArm64.Instruction
|
|||
};
|
||||
|
||||
if (signed)
|
||||
{
|
||||
EmitVectorBinaryOpSx(context, emit);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(context, emit);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
@ -642,7 +676,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorShrImmNarrowOpZx(AILEmitterCtx context, bool round)
|
||||
|
@ -684,7 +721,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (part == 0) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
@ -727,7 +767,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
int part = !scalar && op.RegisterSize == ARegisterSize.Simd128 ? elems : 0;
|
||||
|
||||
if (scalar) EmitVectorZeroLowerTmp(context);
|
||||
if (scalar)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(context);
|
||||
}
|
||||
|
||||
if (part != 0)
|
||||
{
|
||||
|
@ -765,7 +808,10 @@ namespace ChocolArm64.Instruction
|
|||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (part == 0) EmitVectorZeroUpper(context, op.Rd);
|
||||
if (part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
// Dst_64 = (Int(Src_64, Signed) + RoundConst) >> Shift;
|
||||
|
|
|
@ -42,7 +42,9 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (propInfo.PropertyType != typeof(long) &&
|
||||
propInfo.PropertyType != typeof(ulong))
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
context.EmitStintzr(op.Rt);
|
||||
}
|
||||
|
@ -69,7 +71,9 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (propInfo.PropertyType != typeof(long) &&
|
||||
propInfo.PropertyType != typeof(ulong))
|
||||
{
|
||||
context.Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
|
||||
context.EmitCallPropSet(typeof(AThreadState), propName);
|
||||
}
|
||||
|
|
|
@ -28,9 +28,13 @@ namespace ChocolArm64.Instruction
|
|||
else /* if (Shift == 64) */
|
||||
{
|
||||
if (value < 0L)
|
||||
{
|
||||
return -1L;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* if (RoundConst == 1L << (Shift - 1)) */
|
||||
|
@ -40,9 +44,13 @@ namespace ChocolArm64.Instruction
|
|||
long add = value + roundConst;
|
||||
|
||||
if ((~value & (value ^ add)) < 0L)
|
||||
{
|
||||
return (long)((ulong)add >> shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
return add >> shift;
|
||||
}
|
||||
}
|
||||
else /* if (Shift == 64) */
|
||||
{
|
||||
|
@ -56,9 +64,13 @@ namespace ChocolArm64.Instruction
|
|||
if (roundConst == 0L)
|
||||
{
|
||||
if (shift <= 63)
|
||||
{
|
||||
return value >> shift;
|
||||
}
|
||||
else /* if (Shift == 64) */
|
||||
{
|
||||
return 0UL;
|
||||
}
|
||||
}
|
||||
else /* if (RoundConst == 1L << (Shift - 1)) */
|
||||
{
|
||||
|
@ -67,16 +79,24 @@ namespace ChocolArm64.Instruction
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,9 +212,13 @@ namespace ChocolArm64.Instruction
|
|||
state.SetFpsrFlag(FPSR.Qc);
|
||||
|
||||
if (op1 < 0L)
|
||||
{
|
||||
return long.MinValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return long.MaxValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -227,9 +251,13 @@ namespace ChocolArm64.Instruction
|
|||
state.SetFpsrFlag(FPSR.Qc);
|
||||
|
||||
if (op1 < 0L)
|
||||
{
|
||||
return long.MinValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return long.MaxValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -358,7 +386,12 @@ namespace ChocolArm64.Instruction
|
|||
int highBit = size - 2;
|
||||
|
||||
for (int bit = highBit; bit >= 0; bit--)
|
||||
if (((value >> bit) & 0b1) != 0) return (ulong)(highBit - bit);
|
||||
{
|
||||
if (((value >> bit) & 0b1) != 0)
|
||||
{
|
||||
return (ulong)(highBit - bit);
|
||||
}
|
||||
}
|
||||
|
||||
return (ulong)(size - 1);
|
||||
}
|
||||
|
@ -367,7 +400,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
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;
|
||||
if (value == 0ul)
|
||||
{
|
||||
return (ulong)size;
|
||||
}
|
||||
|
||||
int nibbleIdx = size;
|
||||
int preCount, count = 0;
|
||||
|
@ -385,7 +421,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static ulong CountSetBits8(ulong value) // "Size" is 8 (SIMD&FP Inst.).
|
||||
{
|
||||
if (value == 0xfful) return 8ul;
|
||||
if (value == 0xfful)
|
||||
{
|
||||
return 8ul;
|
||||
}
|
||||
|
||||
value = ((value >> 1) & 0x55ul) + (value & 0x55ul);
|
||||
value = ((value >> 2) & 0x33ul) + (value & 0x33ul);
|
||||
|
@ -489,7 +528,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> Decrypt(Vector128<float> value, Vector128<float> roundKey)
|
||||
{
|
||||
if (!Sse.IsSupported) throw new PlatformNotSupportedException();
|
||||
if (!Sse.IsSupported)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
return ACryptoHelper.AesInvSubBytes(ACryptoHelper.AesInvShiftRows(Sse.Xor(value, roundKey)));
|
||||
}
|
||||
|
@ -497,7 +539,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> Encrypt(Vector128<float> value, Vector128<float> roundKey)
|
||||
{
|
||||
if (!Sse.IsSupported) throw new PlatformNotSupportedException();
|
||||
if (!Sse.IsSupported)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
return ACryptoHelper.AesSubBytes(ACryptoHelper.AesShiftRows(Sse.Xor(value, roundKey)));
|
||||
}
|
||||
|
@ -610,7 +655,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
private static void Rol32_256(ref Vector128<float> y, ref Vector128<float> x)
|
||||
{
|
||||
if (!Sse2.IsSupported) throw new PlatformNotSupportedException();
|
||||
if (!Sse2.IsSupported)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
uint yE3 = (uint)VectorExtractIntZx(y, (byte)3, 2);
|
||||
uint xE3 = (uint)VectorExtractIntZx(x, (byte)3, 2);
|
||||
|
@ -726,15 +774,24 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
value = ((value & 0xff00ff00ff00ff00) >> 8) | ((value & 0x00ff00ff00ff00ff) << 8);
|
||||
|
||||
if (size == RevSize.Rev16) return value;
|
||||
if (size == RevSize.Rev16)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16);
|
||||
|
||||
if (size == RevSize.Rev32) return value;
|
||||
if (size == RevSize.Rev32)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
value = ((value & 0xffffffff00000000) >> 32) | ((value & 0x00000000ffffffff) << 32);
|
||||
|
||||
if (size == RevSize.Rev64) return value;
|
||||
if (size == RevSize.Rev64)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(size));
|
||||
}
|
||||
|
@ -744,8 +801,15 @@ namespace ChocolArm64.Instruction
|
|||
public static long SMulHi128(long lhs, long rhs)
|
||||
{
|
||||
long result = (long)UMulHi128((ulong)lhs, (ulong)rhs);
|
||||
if (lhs < 0) result -= rhs;
|
||||
if (rhs < 0) result -= lhs;
|
||||
if (lhs < 0)
|
||||
{
|
||||
result -= rhs;
|
||||
}
|
||||
|
||||
if (rhs < 0)
|
||||
{
|
||||
result -= lhs;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -39,12 +39,20 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
ulong a = index;
|
||||
if (a < 256)
|
||||
{
|
||||
a = (a << 1) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = (a | 1) << 1;
|
||||
}
|
||||
|
||||
ulong b = 256;
|
||||
while (a * (b + 1) * (b + 1) < 1ul << 28) b++;
|
||||
while (a * (b + 1) * (b + 1) < 1ul << 28)
|
||||
{
|
||||
b++;
|
||||
}
|
||||
|
||||
b = (b + 1) >> 1;
|
||||
|
||||
table[index] = (byte)(b & 0xFF);
|
||||
|
@ -67,7 +75,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (xExp >= 2045)
|
||||
{
|
||||
if (xExp == 0x7ff && scaled != 0) return BitConverter.Int64BitsToDouble((long)(xBits | 0x0008000000000000));
|
||||
if (xExp == 0x7ff && scaled != 0)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble((long)(xBits | 0x0008000000000000));
|
||||
}
|
||||
|
||||
// Infinity, or Out of range -> Zero
|
||||
return BitConverter.Int64BitsToDouble((long)xSign);
|
||||
|
@ -75,7 +86,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (xExp == 0)
|
||||
{
|
||||
if (scaled == 0) return BitConverter.Int64BitsToDouble((long)(xSign | 0x7FF0000000000000));
|
||||
if (scaled == 0)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble((long)(xSign | 0x7FF0000000000000));
|
||||
}
|
||||
|
||||
// Denormal
|
||||
if ((scaled & (1ul << 51)) == 0)
|
||||
|
@ -125,11 +139,17 @@ namespace ChocolArm64.Instruction
|
|||
long xExp = (long)((xBits >> 52) & 0x7FF);
|
||||
ulong scaled = xBits & ((1ul << 52) - 1);
|
||||
|
||||
if (xExp == 0x7FF && scaled != 0) return BitConverter.Int64BitsToDouble((long)(xBits | 0x0008000000000000));
|
||||
if (xExp == 0x7FF && scaled != 0)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble((long)(xBits | 0x0008000000000000));
|
||||
}
|
||||
|
||||
if (xExp == 0)
|
||||
{
|
||||
if (scaled == 0) return BitConverter.Int64BitsToDouble((long)(xSign | 0x7FF0000000000000));
|
||||
if (scaled == 0)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble((long)(xSign | 0x7FF0000000000000));
|
||||
}
|
||||
|
||||
// Denormal
|
||||
while ((scaled & (1 << 51)) == 0)
|
||||
|
@ -140,9 +160,15 @@ namespace ChocolArm64.Instruction
|
|||
scaled <<= 1;
|
||||
}
|
||||
|
||||
if (xSign != 0) return BitConverter.Int64BitsToDouble((long)0x7FF8000000000000);
|
||||
if (xSign != 0)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble((long)0x7FF8000000000000);
|
||||
}
|
||||
|
||||
if (xExp == 0x7ff && scaled == 0) return BitConverter.Int64BitsToDouble((long)xSign);
|
||||
if (xExp == 0x7ff && scaled == 0)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble((long)xSign);
|
||||
}
|
||||
|
||||
if (((ulong)xExp & 1) == 1)
|
||||
{
|
||||
|
@ -179,11 +205,18 @@ namespace ChocolArm64.Instruction
|
|||
if (type == FPType.SnaN || type == FPType.QnaN)
|
||||
{
|
||||
if (state.GetFpcrFlag(FPCR.Dn))
|
||||
{
|
||||
result = FpDefaultNaN();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = FpConvertNaN(valueBits);
|
||||
}
|
||||
|
||||
if (type == FPType.SnaN) FpProcessException(FPExc.InvalidOp, state);
|
||||
if (type == FPType.SnaN)
|
||||
{
|
||||
FpProcessException(FPExc.InvalidOp, state);
|
||||
}
|
||||
}
|
||||
else if (type == FPType.Infinity)
|
||||
{
|
||||
|
@ -309,12 +342,18 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
uint biasedExp = (uint)Math.Max(exponent - minimumExp + 1, 0);
|
||||
|
||||
if (biasedExp == 0u) mantissa /= Math.Pow(2d, minimumExp - exponent);
|
||||
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 || state.GetFpcrFlag(FPCR.Ufe))) FpProcessException(FPExc.Underflow, state);
|
||||
if (biasedExp == 0u && (error != 0d || state.GetFpcrFlag(FPCR.Ufe)))
|
||||
{
|
||||
FpProcessException(FPExc.Underflow, state);
|
||||
}
|
||||
|
||||
bool overflowToInf;
|
||||
bool roundUp;
|
||||
|
@ -347,7 +386,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
intMant++;
|
||||
|
||||
if (intMant == (uint)Math.Pow(2d, f)) biasedExp = 1u;
|
||||
if (intMant == (uint)Math.Pow(2d, f))
|
||||
{
|
||||
biasedExp = 1u;
|
||||
}
|
||||
|
||||
if (intMant == (uint)Math.Pow(2d, f + 1))
|
||||
{
|
||||
|
@ -372,7 +414,10 @@ namespace ChocolArm64.Instruction
|
|||
(int)(((sign ? 1u : 0u) << 31) | ((biasedExp & 0xFFu) << 23) | (intMant & 0x007FFFFFu)));
|
||||
}
|
||||
|
||||
if (error != 0d) FpProcessException(FPExc.Inexact, state);
|
||||
if (error != 0d)
|
||||
{
|
||||
FpProcessException(FPExc.Inexact, state);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -388,9 +433,13 @@ namespace ChocolArm64.Instruction
|
|||
int enable = (int)exc + 8;
|
||||
|
||||
if ((state.Fpcr & (1 << enable)) != 0)
|
||||
{
|
||||
throw new NotImplementedException("floating-point trap handling");
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Fpsr |= 1 << (int)exc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -409,13 +458,22 @@ namespace ChocolArm64.Instruction
|
|||
if (type == FPType.SnaN || type == FPType.QnaN)
|
||||
{
|
||||
if (altHp)
|
||||
{
|
||||
resultBits = FpZero(sign);
|
||||
}
|
||||
else if (state.GetFpcrFlag(FPCR.Dn))
|
||||
{
|
||||
resultBits = FpDefaultNaN();
|
||||
}
|
||||
else
|
||||
{
|
||||
resultBits = FpConvertNaN(valueBits);
|
||||
}
|
||||
|
||||
if (type == FPType.SnaN || altHp) FpProcessException(FPExc.InvalidOp, state);
|
||||
if (type == FPType.SnaN || altHp)
|
||||
{
|
||||
FpProcessException(FPExc.InvalidOp, state);
|
||||
}
|
||||
}
|
||||
else if (type == FPType.Infinity)
|
||||
{
|
||||
|
@ -480,7 +538,10 @@ namespace ChocolArm64.Instruction
|
|||
type = FPType.Zero;
|
||||
real = 0d;
|
||||
|
||||
if (frac32 != 0u) FpProcessException(FPExc.InputDenorm, state);
|
||||
if (frac32 != 0u)
|
||||
{
|
||||
FpProcessException(FPExc.InputDenorm, state);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -547,12 +608,18 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
uint biasedExp = (uint)Math.Max(exponent - minimumExp + 1, 0);
|
||||
|
||||
if (biasedExp == 0u) mantissa /= Math.Pow(2d, minimumExp - exponent);
|
||||
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 || state.GetFpcrFlag(FPCR.Ufe))) FpProcessException(FPExc.Underflow, state);
|
||||
if (biasedExp == 0u && (error != 0d || state.GetFpcrFlag(FPCR.Ufe)))
|
||||
{
|
||||
FpProcessException(FPExc.Underflow, state);
|
||||
}
|
||||
|
||||
bool overflowToInf;
|
||||
bool roundUp;
|
||||
|
@ -585,7 +652,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
intMant++;
|
||||
|
||||
if (intMant == (uint)Math.Pow(2d, f)) biasedExp = 1u;
|
||||
if (intMant == (uint)Math.Pow(2d, f))
|
||||
{
|
||||
biasedExp = 1u;
|
||||
}
|
||||
|
||||
if (intMant == (uint)Math.Pow(2d, f + 1))
|
||||
{
|
||||
|
@ -627,7 +697,10 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
if (error != 0d) FpProcessException(FPExc.Inexact, state);
|
||||
if (error != 0d)
|
||||
{
|
||||
FpProcessException(FPExc.Inexact, state);
|
||||
}
|
||||
|
||||
return resultBits;
|
||||
}
|
||||
|
@ -642,9 +715,13 @@ namespace ChocolArm64.Instruction
|
|||
int enable = (int)exc + 8;
|
||||
|
||||
if ((state.Fpcr & (1 << enable)) != 0)
|
||||
{
|
||||
throw new NotImplementedException("floating-point trap handling");
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Fpsr |= 1 << (int)exc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -715,7 +792,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
result = FpInfinity(sign1 ^ sign2);
|
||||
|
||||
if (!inf1) FpProcessException(FPExc.DivideByZero, state);
|
||||
if (!inf1)
|
||||
{
|
||||
FpProcessException(FPExc.DivideByZero, state);
|
||||
}
|
||||
}
|
||||
else if (zero1 || inf2)
|
||||
{
|
||||
|
@ -744,20 +824,32 @@ namespace ChocolArm64.Instruction
|
|||
if (value1 > value2)
|
||||
{
|
||||
if (type1 == FPType.Infinity)
|
||||
{
|
||||
result = FpInfinity(sign1);
|
||||
}
|
||||
else if (type1 == FPType.Zero)
|
||||
{
|
||||
result = FpZero(sign1 && sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type2 == FPType.Infinity)
|
||||
{
|
||||
result = FpInfinity(sign2);
|
||||
}
|
||||
else if (type2 == FPType.Zero)
|
||||
{
|
||||
result = FpZero(sign1 && sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,8 +864,13 @@ namespace ChocolArm64.Instruction
|
|||
value2.FpUnpack(out FPType type2, out _, out _);
|
||||
|
||||
if (type1 == FPType.QnaN && type2 != FPType.QnaN)
|
||||
{
|
||||
value1 = FpInfinity(true);
|
||||
else if (type1 != FPType.QnaN && type2 == FPType.QnaN) value2 = FpInfinity(true);
|
||||
}
|
||||
else if (type1 != FPType.QnaN && type2 == FPType.QnaN)
|
||||
{
|
||||
value2 = FpInfinity(true);
|
||||
}
|
||||
|
||||
return FpMax(value1, value2, state);
|
||||
}
|
||||
|
@ -792,20 +889,32 @@ namespace ChocolArm64.Instruction
|
|||
if (value1 < value2)
|
||||
{
|
||||
if (type1 == FPType.Infinity)
|
||||
{
|
||||
result = FpInfinity(sign1);
|
||||
}
|
||||
else if (type1 == FPType.Zero)
|
||||
{
|
||||
result = FpZero(sign1 || sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type2 == FPType.Infinity)
|
||||
{
|
||||
result = FpInfinity(sign2);
|
||||
}
|
||||
else if (type2 == FPType.Zero)
|
||||
{
|
||||
result = FpZero(sign1 || sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -820,8 +929,13 @@ namespace ChocolArm64.Instruction
|
|||
value2.FpUnpack(out FPType type2, out _, out _);
|
||||
|
||||
if (type1 == FPType.QnaN && type2 != FPType.QnaN)
|
||||
{
|
||||
value1 = FpInfinity(false);
|
||||
else if (type1 != FPType.QnaN && type2 == FPType.QnaN) value2 = FpInfinity(false);
|
||||
}
|
||||
else if (type1 != FPType.QnaN && type2 == FPType.QnaN)
|
||||
{
|
||||
value2 = FpInfinity(false);
|
||||
}
|
||||
|
||||
return FpMin(value1, value2, state);
|
||||
}
|
||||
|
@ -946,13 +1060,21 @@ namespace ChocolArm64.Instruction
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -975,11 +1097,17 @@ namespace ChocolArm64.Instruction
|
|||
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 = 2f + value1 * value2;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1026,11 +1154,17 @@ namespace ChocolArm64.Instruction
|
|||
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 = (3f + value1 * value2) / 2f;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1150,9 +1284,13 @@ namespace ChocolArm64.Instruction
|
|||
if ((valueBits & 0x7F800000u) == 0u)
|
||||
{
|
||||
if ((valueBits & 0x007FFFFFu) == 0u)
|
||||
{
|
||||
type = FPType.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = FPType.Nonzero;
|
||||
}
|
||||
}
|
||||
else if ((~valueBits & 0x7F800000u) == 0u)
|
||||
{
|
||||
|
@ -1188,12 +1326,21 @@ namespace ChocolArm64.Instruction
|
|||
done = true;
|
||||
|
||||
if (type1 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type1, op1, state);
|
||||
}
|
||||
else if (type2 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type2, op2, state);
|
||||
}
|
||||
else if (type1 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type1, op1, state);
|
||||
else if (type2 == FPType.QnaN) return FpProcessNaN(type2, op2, state);
|
||||
}
|
||||
else if (type2 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type2, op2, state);
|
||||
}
|
||||
|
||||
done = false;
|
||||
|
||||
|
@ -1213,16 +1360,29 @@ namespace ChocolArm64.Instruction
|
|||
done = true;
|
||||
|
||||
if (type1 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type1, op1, state);
|
||||
}
|
||||
else if (type2 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type2, op2, state);
|
||||
}
|
||||
else if (type3 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type3, op3, state);
|
||||
}
|
||||
else if (type1 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type1, op1, state);
|
||||
}
|
||||
else if (type2 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type2, op2, state);
|
||||
else if (type3 == FPType.QnaN) return FpProcessNaN(type3, op3, state);
|
||||
}
|
||||
else if (type3 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type3, op3, state);
|
||||
}
|
||||
|
||||
done = false;
|
||||
|
||||
|
@ -1238,7 +1398,10 @@ namespace ChocolArm64.Instruction
|
|||
FpProcessException(FPExc.InvalidOp, state);
|
||||
}
|
||||
|
||||
if (state.GetFpcrFlag(FPCR.Dn)) return FpDefaultNaN();
|
||||
if (state.GetFpcrFlag(FPCR.Dn))
|
||||
{
|
||||
return FpDefaultNaN();
|
||||
}
|
||||
|
||||
return BitConverter.Int32BitsToSingle((int)op);
|
||||
}
|
||||
|
@ -1248,9 +1411,13 @@ namespace ChocolArm64.Instruction
|
|||
int enable = (int)exc + 8;
|
||||
|
||||
if ((state.Fpcr & (1 << enable)) != 0)
|
||||
{
|
||||
throw new NotImplementedException("floating-point trap handling");
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Fpsr |= 1 << (int)exc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1321,7 +1488,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
result = FpInfinity(sign1 ^ sign2);
|
||||
|
||||
if (!inf1) FpProcessException(FPExc.DivideByZero, state);
|
||||
if (!inf1)
|
||||
{
|
||||
FpProcessException(FPExc.DivideByZero, state);
|
||||
}
|
||||
}
|
||||
else if (zero1 || inf2)
|
||||
{
|
||||
|
@ -1350,20 +1520,32 @@ namespace ChocolArm64.Instruction
|
|||
if (value1 > value2)
|
||||
{
|
||||
if (type1 == FPType.Infinity)
|
||||
{
|
||||
result = FpInfinity(sign1);
|
||||
}
|
||||
else if (type1 == FPType.Zero)
|
||||
{
|
||||
result = FpZero(sign1 && sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type2 == FPType.Infinity)
|
||||
{
|
||||
result = FpInfinity(sign2);
|
||||
}
|
||||
else if (type2 == FPType.Zero)
|
||||
{
|
||||
result = FpZero(sign1 && sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1378,8 +1560,13 @@ namespace ChocolArm64.Instruction
|
|||
value2.FpUnpack(out FPType type2, out _, out _);
|
||||
|
||||
if (type1 == FPType.QnaN && type2 != FPType.QnaN)
|
||||
{
|
||||
value1 = FpInfinity(true);
|
||||
else if (type1 != FPType.QnaN && type2 == FPType.QnaN) value2 = FpInfinity(true);
|
||||
}
|
||||
else if (type1 != FPType.QnaN && type2 == FPType.QnaN)
|
||||
{
|
||||
value2 = FpInfinity(true);
|
||||
}
|
||||
|
||||
return FpMax(value1, value2, state);
|
||||
}
|
||||
|
@ -1398,20 +1585,32 @@ namespace ChocolArm64.Instruction
|
|||
if (value1 < value2)
|
||||
{
|
||||
if (type1 == FPType.Infinity)
|
||||
{
|
||||
result = FpInfinity(sign1);
|
||||
}
|
||||
else if (type1 == FPType.Zero)
|
||||
{
|
||||
result = FpZero(sign1 || sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type2 == FPType.Infinity)
|
||||
{
|
||||
result = FpInfinity(sign2);
|
||||
}
|
||||
else if (type2 == FPType.Zero)
|
||||
{
|
||||
result = FpZero(sign1 || sign2);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = value2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1426,8 +1625,13 @@ namespace ChocolArm64.Instruction
|
|||
value2.FpUnpack(out FPType type2, out _, out _);
|
||||
|
||||
if (type1 == FPType.QnaN && type2 != FPType.QnaN)
|
||||
{
|
||||
value1 = FpInfinity(false);
|
||||
else if (type1 != FPType.QnaN && type2 == FPType.QnaN) value2 = FpInfinity(false);
|
||||
}
|
||||
else if (type1 != FPType.QnaN && type2 == FPType.QnaN)
|
||||
{
|
||||
value2 = FpInfinity(false);
|
||||
}
|
||||
|
||||
return FpMin(value1, value2, state);
|
||||
}
|
||||
|
@ -1552,13 +1756,21 @@ namespace ChocolArm64.Instruction
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1581,11 +1793,17 @@ namespace ChocolArm64.Instruction
|
|||
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 = 2d + value1 * value2;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1632,11 +1850,17 @@ namespace ChocolArm64.Instruction
|
|||
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 = (3d + value1 * value2) / 2d;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1756,9 +1980,13 @@ namespace ChocolArm64.Instruction
|
|||
if ((valueBits & 0x7FF0000000000000ul) == 0ul)
|
||||
{
|
||||
if ((valueBits & 0x000FFFFFFFFFFFFFul) == 0ul)
|
||||
{
|
||||
type = FPType.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = FPType.Nonzero;
|
||||
}
|
||||
}
|
||||
else if ((~valueBits & 0x7FF0000000000000ul) == 0ul)
|
||||
{
|
||||
|
@ -1794,12 +2022,21 @@ namespace ChocolArm64.Instruction
|
|||
done = true;
|
||||
|
||||
if (type1 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type1, op1, state);
|
||||
}
|
||||
else if (type2 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type2, op2, state);
|
||||
}
|
||||
else if (type1 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type1, op1, state);
|
||||
else if (type2 == FPType.QnaN) return FpProcessNaN(type2, op2, state);
|
||||
}
|
||||
else if (type2 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type2, op2, state);
|
||||
}
|
||||
|
||||
done = false;
|
||||
|
||||
|
@ -1819,16 +2056,29 @@ namespace ChocolArm64.Instruction
|
|||
done = true;
|
||||
|
||||
if (type1 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type1, op1, state);
|
||||
}
|
||||
else if (type2 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type2, op2, state);
|
||||
}
|
||||
else if (type3 == FPType.SnaN)
|
||||
{
|
||||
return FpProcessNaN(type3, op3, state);
|
||||
}
|
||||
else if (type1 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type1, op1, state);
|
||||
}
|
||||
else if (type2 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type2, op2, state);
|
||||
else if (type3 == FPType.QnaN) return FpProcessNaN(type3, op3, state);
|
||||
}
|
||||
else if (type3 == FPType.QnaN)
|
||||
{
|
||||
return FpProcessNaN(type3, op3, state);
|
||||
}
|
||||
|
||||
done = false;
|
||||
|
||||
|
@ -1844,7 +2094,10 @@ namespace ChocolArm64.Instruction
|
|||
FpProcessException(FPExc.InvalidOp, state);
|
||||
}
|
||||
|
||||
if (state.GetFpcrFlag(FPCR.Dn)) return FpDefaultNaN();
|
||||
if (state.GetFpcrFlag(FPCR.Dn))
|
||||
{
|
||||
return FpDefaultNaN();
|
||||
}
|
||||
|
||||
return BitConverter.Int64BitsToDouble((long)op);
|
||||
}
|
||||
|
@ -1854,9 +2107,13 @@ namespace ChocolArm64.Instruction
|
|||
int enable = (int)exc + 8;
|
||||
|
||||
if ((state.Fpcr & (1 << enable)) != 0)
|
||||
{
|
||||
throw new NotImplementedException("floating-point trap handling");
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Fpsr |= 1 << (int)exc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,10 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
static AVectorHelper()
|
||||
{
|
||||
if (!Sse2.IsSupported) throw new PlatformNotSupportedException();
|
||||
if (!Sse2.IsSupported)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
_zero32_128Mask = Sse.StaticCast<uint, float>(Sse2.SetVector128(0, 0, 0, 0xffffffff));
|
||||
}
|
||||
|
@ -33,7 +36,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int SatF32ToS32(float value)
|
||||
{
|
||||
if (float.IsNaN(value)) return 0;
|
||||
if (float.IsNaN(value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value > int.MaxValue ? int.MaxValue :
|
||||
value < int.MinValue ? int.MinValue : (int)value;
|
||||
|
@ -42,7 +48,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long SatF32ToS64(float value)
|
||||
{
|
||||
if (float.IsNaN(value)) return 0;
|
||||
if (float.IsNaN(value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value > long.MaxValue ? long.MaxValue :
|
||||
value < long.MinValue ? long.MinValue : (long)value;
|
||||
|
@ -51,7 +60,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint SatF32ToU32(float value)
|
||||
{
|
||||
if (float.IsNaN(value)) return 0;
|
||||
if (float.IsNaN(value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value > uint.MaxValue ? uint.MaxValue :
|
||||
value < uint.MinValue ? uint.MinValue : (uint)value;
|
||||
|
@ -60,7 +72,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong SatF32ToU64(float value)
|
||||
{
|
||||
if (float.IsNaN(value)) return 0;
|
||||
if (float.IsNaN(value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value > ulong.MaxValue ? ulong.MaxValue :
|
||||
value < ulong.MinValue ? ulong.MinValue : (ulong)value;
|
||||
|
@ -69,7 +84,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int SatF64ToS32(double value)
|
||||
{
|
||||
if (double.IsNaN(value)) return 0;
|
||||
if (double.IsNaN(value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value > int.MaxValue ? int.MaxValue :
|
||||
value < int.MinValue ? int.MinValue : (int)value;
|
||||
|
@ -78,7 +96,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long SatF64ToS64(double value)
|
||||
{
|
||||
if (double.IsNaN(value)) return 0;
|
||||
if (double.IsNaN(value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value > long.MaxValue ? long.MaxValue :
|
||||
value < long.MinValue ? long.MinValue : (long)value;
|
||||
|
@ -87,7 +108,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint SatF64ToU32(double value)
|
||||
{
|
||||
if (double.IsNaN(value)) return 0;
|
||||
if (double.IsNaN(value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value > uint.MaxValue ? uint.MaxValue :
|
||||
value < uint.MinValue ? uint.MinValue : (uint)value;
|
||||
|
@ -96,7 +120,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong SatF64ToU64(double value)
|
||||
{
|
||||
if (double.IsNaN(value)) return 0;
|
||||
if (double.IsNaN(value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value > ulong.MaxValue ? ulong.MaxValue :
|
||||
value < ulong.MinValue ? ulong.MinValue : (ulong)value;
|
||||
|
@ -203,14 +230,21 @@ namespace ChocolArm64.Instruction
|
|||
byte[] table = new byte[tb.Length * 16];
|
||||
|
||||
for (byte index = 0; index < tb.Length; index++)
|
||||
for (byte index2 = 0; index2 < 16; index2++)
|
||||
table[index * 16 + index2] = (byte)VectorExtractIntZx(tb[index], index2, 0);
|
||||
{
|
||||
for (byte index2 = 0; index2 < 16; index2++)
|
||||
{
|
||||
table[index * 16 + index2] = (byte)VectorExtractIntZx(tb[index], index2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (byte index = 0; index < bytes; index++)
|
||||
{
|
||||
byte tblIdx = (byte)VectorExtractIntZx(vector, index, 0);
|
||||
|
||||
if (tblIdx < table.Length) res = VectorInsertInt(table[tblIdx], res, index, 0);
|
||||
if (tblIdx < table.Length)
|
||||
{
|
||||
res = VectorInsertInt(table[tblIdx], res, index, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -220,8 +254,13 @@ namespace ChocolArm64.Instruction
|
|||
public static double VectorExtractDouble(Vector128<float> vector, byte index)
|
||||
{
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble(Sse41.Extract(Sse.StaticCast<float, long>(vector), index));
|
||||
else if (Sse2.IsSupported) return BitConverter.Int64BitsToDouble((long)VectorExtractIntZx(vector, index, 3));
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble((long)VectorExtractIntZx(vector, index, 3));
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -232,28 +271,48 @@ namespace ChocolArm64.Instruction
|
|||
if (Sse41.IsSupported)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return (sbyte)Sse41.Extract(Sse.StaticCast<float, byte>(vector), index);
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
return (short)Sse2.Extract(Sse.StaticCast<float, ushort>(vector), index);
|
||||
}
|
||||
else if (size == 2)
|
||||
{
|
||||
return Sse41.Extract(Sse.StaticCast<float, int>(vector), index);
|
||||
}
|
||||
else if (size == 3)
|
||||
{
|
||||
return Sse41.Extract(Sse.StaticCast<float, long>(vector), index);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return (sbyte)VectorExtractIntZx(vector, index, size);
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
return (short)VectorExtractIntZx(vector, index, size);
|
||||
}
|
||||
else if (size == 2)
|
||||
{
|
||||
return (int)VectorExtractIntZx(vector, index, size);
|
||||
}
|
||||
else if (size == 3)
|
||||
{
|
||||
return (long)VectorExtractIntZx(vector, index, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
|
@ -265,15 +324,25 @@ namespace ChocolArm64.Instruction
|
|||
if (Sse41.IsSupported)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return Sse41.Extract(Sse.StaticCast<float, byte>(vector), index);
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
return Sse2.Extract(Sse.StaticCast<float, ushort>(vector), index);
|
||||
}
|
||||
else if (size == 2)
|
||||
{
|
||||
return Sse41.Extract(Sse.StaticCast<float, uint>(vector), index);
|
||||
}
|
||||
else if (size == 3)
|
||||
{
|
||||
return Sse41.Extract(Sse.StaticCast<float, ulong>(vector), index);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
|
@ -295,7 +364,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
ushort value1 = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)(shortIdx + 1));
|
||||
|
||||
if (size == 2) return (uint)(value | (value1 << 16));
|
||||
if (size == 2)
|
||||
{
|
||||
return (uint)(value | (value1 << 16));
|
||||
}
|
||||
|
||||
ushort value2 = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)(shortIdx + 2));
|
||||
ushort value3 = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)(shortIdx + 3));
|
||||
|
@ -346,15 +418,25 @@ namespace ChocolArm64.Instruction
|
|||
if (Sse41.IsSupported)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return Sse.StaticCast<byte, float>(Sse41.Insert(Sse.StaticCast<float, byte>(vector), (byte)value, index));
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(vector), (ushort)value, index));
|
||||
}
|
||||
else if (size == 2)
|
||||
{
|
||||
return Sse.StaticCast<uint, float>(Sse41.Insert(Sse.StaticCast<float, uint>(vector), (uint)value, index));
|
||||
}
|
||||
else if (size == 3)
|
||||
{
|
||||
return Sse.StaticCast<ulong, float>(Sse41.Insert(Sse.StaticCast<float, ulong>(vector), value, index));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
|
@ -411,15 +493,25 @@ namespace ChocolArm64.Instruction
|
|||
//produce a single INSERTPS instruction instead of the
|
||||
//jump table fallback.
|
||||
if (index == 0)
|
||||
{
|
||||
return Sse41.Insert(vector, value, 0x00);
|
||||
}
|
||||
else if (index == 1)
|
||||
{
|
||||
return Sse41.Insert(vector, value, 0x10);
|
||||
}
|
||||
else if (index == 2)
|
||||
{
|
||||
return Sse41.Insert(vector, value, 0x20);
|
||||
}
|
||||
else if (index == 3)
|
||||
{
|
||||
return Sse41.Insert(vector, value, 0x30);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
|
@ -449,7 +541,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<sbyte> VectorSByteZero()
|
||||
{
|
||||
if (Sse2.IsSupported) return Sse2.SetZeroVector128<sbyte>();
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<sbyte>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -457,7 +552,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<short> VectorInt16Zero()
|
||||
{
|
||||
if (Sse2.IsSupported) return Sse2.SetZeroVector128<short>();
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<short>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -465,7 +563,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<int> VectorInt32Zero()
|
||||
{
|
||||
if (Sse2.IsSupported) return Sse2.SetZeroVector128<int>();
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<int>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -473,7 +574,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<long> VectorInt64Zero()
|
||||
{
|
||||
if (Sse2.IsSupported) return Sse2.SetZeroVector128<long>();
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<long>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -481,7 +585,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorSingleZero()
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.SetZeroVector128();
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.SetZeroVector128();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -489,7 +596,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<double> VectorDoubleZero()
|
||||
{
|
||||
if (Sse2.IsSupported) return Sse2.SetZeroVector128<double>();
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<double>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -497,7 +607,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorZero32_128(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.And(vector, _zero32_128Mask);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.And(vector, _zero32_128Mask);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -505,7 +618,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<sbyte> VectorSingleToSByte(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<float, sbyte>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, sbyte>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -513,7 +629,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<short> VectorSingleToInt16(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<float, short>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, short>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -521,7 +640,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<int> VectorSingleToInt32(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<float, int>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, int>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -529,7 +651,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<long> VectorSingleToInt64(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<float, long>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, long>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -537,7 +662,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<byte> VectorSingleToByte(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<float, byte>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, byte>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -545,7 +673,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<ushort> VectorSingleToUInt16(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<float, ushort>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, ushort>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -553,7 +684,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<uint> VectorSingleToUInt32(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<float, uint>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, uint>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -561,7 +695,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<ulong> VectorSingleToUInt64(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<float, ulong>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, ulong>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -569,7 +706,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<double> VectorSingleToDouble(Vector128<float> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<float, double>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, double>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -577,7 +717,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorSByteToSingle(Vector128<sbyte> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<sbyte, float>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<sbyte, float>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -585,7 +728,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorInt16ToSingle(Vector128<short> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<short, float>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<short, float>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -593,7 +739,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorInt32ToSingle(Vector128<int> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<int, float>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<int, float>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -601,7 +750,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorInt64ToSingle(Vector128<long> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<long, float>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<long, float>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -609,7 +761,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorByteToSingle(Vector128<byte> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<byte, float>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<byte, float>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -617,7 +772,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorUInt16ToSingle(Vector128<ushort> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<ushort, float>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<ushort, float>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -625,7 +783,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorUInt32ToSingle(Vector128<uint> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<uint, float>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<uint, float>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -633,7 +794,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorUInt64ToSingle(Vector128<ulong> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<ulong, float>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<ulong, float>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
@ -641,7 +805,10 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorDoubleToSingle(Vector128<double> vector)
|
||||
{
|
||||
if (Sse.IsSupported) return Sse.StaticCast<double, float>(vector);
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<double, float>(vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
|
|
@ -13,7 +13,10 @@ namespace ChocolArm64.Instruction32
|
|||
{
|
||||
A32OpCodeBImmAl op = (A32OpCodeBImmAl)opCode;
|
||||
|
||||
if (IsConditionTrue(state, op.Cond)) BranchWritePc(state, GetPc(state) + (uint)op.Imm);
|
||||
if (IsConditionTrue(state, op.Cond))
|
||||
{
|
||||
BranchWritePc(state, GetPc(state) + (uint)op.Imm);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Bl(AThreadState state, AMemory memory, AOpCode opCode)
|
||||
|
@ -35,13 +38,23 @@ namespace ChocolArm64.Instruction32
|
|||
uint pc = GetPc(state);
|
||||
|
||||
if (state.Thumb)
|
||||
{
|
||||
state.R14 = pc | 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.R14 = pc - 4U;
|
||||
}
|
||||
|
||||
if (x) state.Thumb = !state.Thumb;
|
||||
if (x)
|
||||
{
|
||||
state.Thumb = !state.Thumb;
|
||||
}
|
||||
|
||||
if (!state.Thumb) pc &= ~3U;
|
||||
if (!state.Thumb)
|
||||
{
|
||||
pc &= ~3U;
|
||||
}
|
||||
|
||||
BranchWritePc(state, pc + (uint)op.Imm);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,10 @@ namespace ChocolArm64.Instruction32
|
|||
|
||||
public static unsafe uint GetReg(AThreadState state, int reg)
|
||||
{
|
||||
if ((uint)reg > 15) throw new ArgumentOutOfRangeException(nameof(reg));
|
||||
if ((uint)reg > 15)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(reg));
|
||||
}
|
||||
|
||||
fixed (uint* ptr = &state.R0)
|
||||
{
|
||||
|
@ -41,7 +44,10 @@ namespace ChocolArm64.Instruction32
|
|||
|
||||
public static unsafe void SetReg(AThreadState state, int reg, uint value)
|
||||
{
|
||||
if ((uint)reg > 15) throw new ArgumentOutOfRangeException(nameof(reg));
|
||||
if ((uint)reg > 15)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(reg));
|
||||
}
|
||||
|
||||
fixed (uint* ptr = &state.R0)
|
||||
{
|
||||
|
|
|
@ -66,7 +66,10 @@ namespace ChocolArm64.Memory
|
|||
|
||||
_pageTable = (byte***)Marshal.AllocHGlobal(PtLvl0Size * IntPtr.Size);
|
||||
|
||||
for (int l0 = 0; l0 < PtLvl0Size; l0++) _pageTable[l0] = null;
|
||||
for (int l0 = 0; l0 < PtLvl0Size; l0++)
|
||||
{
|
||||
_pageTable[l0] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveMonitor(int core)
|
||||
|
@ -86,7 +89,12 @@ namespace ChocolArm64.Memory
|
|||
lock (_monitors)
|
||||
{
|
||||
foreach (ArmMonitor mon in _monitors.Values)
|
||||
if (mon.Position == position && mon.ExState) mon.ExState = false;
|
||||
{
|
||||
if (mon.Position == position && mon.ExState)
|
||||
{
|
||||
mon.ExState = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_monitors.TryGetValue(core, out ArmMonitor threadMon))
|
||||
{
|
||||
|
@ -108,18 +116,27 @@ namespace ChocolArm64.Memory
|
|||
|
||||
Monitor.Enter(_monitors);
|
||||
|
||||
if (!_monitors.TryGetValue(core, out ArmMonitor threadMon)) return false;
|
||||
if (!_monitors.TryGetValue(core, out ArmMonitor threadMon))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool exState = threadMon.HasExclusiveAccess(position);
|
||||
|
||||
if (!exState) Monitor.Exit(_monitors);
|
||||
if (!exState)
|
||||
{
|
||||
Monitor.Exit(_monitors);
|
||||
}
|
||||
|
||||
return exState;
|
||||
}
|
||||
|
||||
public void ClearExclusiveForStore(int core)
|
||||
{
|
||||
if (_monitors.TryGetValue(core, out ArmMonitor threadMon)) threadMon.ExState = false;
|
||||
if (_monitors.TryGetValue(core, out ArmMonitor threadMon))
|
||||
{
|
||||
threadMon.ExState = false;
|
||||
}
|
||||
|
||||
Monitor.Exit(_monitors);
|
||||
}
|
||||
|
@ -128,7 +145,10 @@ namespace ChocolArm64.Memory
|
|||
{
|
||||
lock (_monitors)
|
||||
{
|
||||
if (_monitors.TryGetValue(core, out ArmMonitor threadMon)) threadMon.ExState = false;
|
||||
if (_monitors.TryGetValue(core, out ArmMonitor threadMon))
|
||||
{
|
||||
threadMon.ExState = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +159,12 @@ namespace ChocolArm64.Memory
|
|||
lock (_monitors)
|
||||
{
|
||||
foreach (ArmMonitor mon in _monitors.Values)
|
||||
if (mon.Position == maskedPosition && mon.ExState) mon.ExState = false;
|
||||
{
|
||||
if (mon.Position == maskedPosition && mon.ExState)
|
||||
{
|
||||
mon.ExState = false;
|
||||
}
|
||||
}
|
||||
|
||||
WriteInt32(position, value);
|
||||
}
|
||||
|
@ -188,50 +213,73 @@ namespace ChocolArm64.Memory
|
|||
public Vector128<float> ReadVector8(long position)
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<byte, float>(Sse2.SetVector128(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ReadByte(position)));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vector128<float> ReadVector16(long position)
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse2.SetZeroVector128<ushort>(), ReadUInt16(position), 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vector128<float> ReadVector32(long position)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.LoadScalarVector128((float*)Translate(position));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vector128<float> ReadVector64(long position)
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<double, float>(Sse2.LoadScalarVector128((double*)Translate(position)));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vector128<float> ReadVector128(long position)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.LoadVector128((float*)Translate(position));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ReadBytes(long position, long size)
|
||||
{
|
||||
if ((uint)size > int.MaxValue) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
if ((uint)size > int.MaxValue)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
EnsureRangeIsValid(position, size);
|
||||
|
||||
|
@ -294,47 +342,69 @@ namespace ChocolArm64.Memory
|
|||
public void WriteVector8(long position, Vector128<float> value)
|
||||
{
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
WriteByte(position, Sse41.Extract(Sse.StaticCast<float, byte>(value), 0));
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
WriteByte(position, (byte)Sse2.Extract(Sse.StaticCast<float, ushort>(value), 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector16(long position, Vector128<float> value)
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
WriteUInt16(position, Sse2.Extract(Sse.StaticCast<float, ushort>(value), 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector32(long position, Vector128<float> value)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
Sse.StoreScalar((float*)TranslateWrite(position), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector64(long position, Vector128<float> value)
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
Sse2.StoreScalar((double*)TranslateWrite(position), Sse.StaticCast<float, double>(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector128(long position, Vector128<float> value)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
Sse.Store((float*)TranslateWrite(position), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteBytes(long position, byte[] data)
|
||||
|
@ -379,12 +449,18 @@ namespace ChocolArm64.Memory
|
|||
|
||||
public bool IsMapped(long position)
|
||||
{
|
||||
if (!IsValidPosition(position)) return false;
|
||||
if (!IsValidPosition(position))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long l0 = (position >> PtLvl0Bit) & PtLvl0Mask;
|
||||
long l1 = (position >> PtLvl1Bit) & PtLvl1Mask;
|
||||
|
||||
if (_pageTable[l0] == null) return false;
|
||||
if (_pageTable[l0] == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _pageTable[l0][l1] != null || _observedPages.ContainsKey(position >> PtPageBits);
|
||||
}
|
||||
|
@ -405,15 +481,24 @@ namespace ChocolArm64.Memory
|
|||
|
||||
byte** lvl1 = _pageTable[l0];
|
||||
|
||||
if (position >> (PtLvl0Bit + PtLvl0Bits) != 0) goto Unmapped;
|
||||
if (position >> (PtLvl0Bit + PtLvl0Bits) != 0)
|
||||
{
|
||||
goto Unmapped;
|
||||
}
|
||||
|
||||
if (lvl1 == null) goto Unmapped;
|
||||
if (lvl1 == null)
|
||||
{
|
||||
goto Unmapped;
|
||||
}
|
||||
|
||||
position &= PageMask;
|
||||
|
||||
byte* ptr = lvl1[l1];
|
||||
|
||||
if (ptr == null) goto Unmapped;
|
||||
if (ptr == null)
|
||||
{
|
||||
goto Unmapped;
|
||||
}
|
||||
|
||||
return ptr + position;
|
||||
|
||||
|
@ -425,7 +510,10 @@ Unmapped:
|
|||
{
|
||||
long key = position >> PtPageBits;
|
||||
|
||||
if (_observedPages.TryGetValue(key, out IntPtr ptr)) return (byte*)ptr + (position & PageMask);
|
||||
if (_observedPages.TryGetValue(key, out IntPtr ptr))
|
||||
{
|
||||
return (byte*)ptr + (position & PageMask);
|
||||
}
|
||||
|
||||
InvalidAccess?.Invoke(this, new AInvalidAccessEventArgs(position));
|
||||
|
||||
|
@ -441,15 +529,24 @@ Unmapped:
|
|||
|
||||
byte** lvl1 = _pageTable[l0];
|
||||
|
||||
if (position >> (PtLvl0Bit + PtLvl0Bits) != 0) goto Unmapped;
|
||||
if (position >> (PtLvl0Bit + PtLvl0Bits) != 0)
|
||||
{
|
||||
goto Unmapped;
|
||||
}
|
||||
|
||||
if (lvl1 == null) goto Unmapped;
|
||||
if (lvl1 == null)
|
||||
{
|
||||
goto Unmapped;
|
||||
}
|
||||
|
||||
position &= PageMask;
|
||||
|
||||
byte* ptr = lvl1[l1];
|
||||
|
||||
if (ptr == null) goto Unmapped;
|
||||
if (ptr == null)
|
||||
{
|
||||
goto Unmapped;
|
||||
}
|
||||
|
||||
return ptr + position;
|
||||
|
||||
|
@ -483,13 +580,19 @@ Unmapped:
|
|||
|
||||
va += PageSize;
|
||||
|
||||
if (ptr != null) ptr += PageSize;
|
||||
if (ptr != null)
|
||||
{
|
||||
ptr += PageSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPtEntry(long position, byte* ptr)
|
||||
{
|
||||
if (!IsValidPosition(position)) throw new ArgumentOutOfRangeException(nameof(position));
|
||||
if (!IsValidPosition(position))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(position));
|
||||
}
|
||||
|
||||
long l0 = (position >> PtLvl0Bit) & PtLvl0Mask;
|
||||
long l1 = (position >> PtLvl1Bit) & PtLvl1Mask;
|
||||
|
@ -498,7 +601,10 @@ Unmapped:
|
|||
{
|
||||
byte** lvl1 = (byte**)Marshal.AllocHGlobal(PtLvl1Size * IntPtr.Size);
|
||||
|
||||
for (int zl1 = 0; zl1 < PtLvl1Size; zl1++) lvl1[zl1] = null;
|
||||
for (int zl1 = 0; zl1 < PtLvl1Size; zl1++)
|
||||
{
|
||||
lvl1[zl1] = null;
|
||||
}
|
||||
|
||||
Thread.MemoryBarrier();
|
||||
|
||||
|
@ -540,7 +646,12 @@ Unmapped:
|
|||
byte** lvl1 = _pageTable[l0];
|
||||
|
||||
if (lvl1 != null)
|
||||
if (modified[page] = lvl1[l1] != null) count++;
|
||||
{
|
||||
if (modified[page] = lvl1[l1] != null)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetPtEntry(position, null);
|
||||
|
@ -560,7 +671,10 @@ Unmapped:
|
|||
{
|
||||
lock (_observedPages)
|
||||
{
|
||||
if (_observedPages.TryRemove(position >> PtPageBits, out IntPtr ptr)) SetPtEntry(position, (byte*)ptr);
|
||||
if (_observedPages.TryRemove(position >> PtPageBits, out IntPtr ptr))
|
||||
{
|
||||
SetPtEntry(position, (byte*)ptr);
|
||||
}
|
||||
}
|
||||
|
||||
position += PageSize;
|
||||
|
@ -586,7 +700,10 @@ Unmapped:
|
|||
{
|
||||
long pa = GetPhysicalAddress(position);
|
||||
|
||||
if (pa != expectedPa) throw new VmmAccessException(position, size);
|
||||
if (pa != expectedPa)
|
||||
{
|
||||
throw new VmmAccessException(position, size);
|
||||
}
|
||||
|
||||
position += PageSize;
|
||||
expectedPa += PageSize;
|
||||
|
@ -605,11 +722,17 @@ Unmapped:
|
|||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_pageTable == null) return;
|
||||
if (_pageTable == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int l0 = 0; l0 < PtLvl0Size; l0++)
|
||||
{
|
||||
if (_pageTable[l0] != null) Marshal.FreeHGlobal((IntPtr)_pageTable[l0]);
|
||||
if (_pageTable[l0] != null)
|
||||
{
|
||||
Marshal.FreeHGlobal((IntPtr)_pageTable[l0]);
|
||||
}
|
||||
|
||||
_pageTable[l0] = null;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,15 @@ namespace ChocolArm64.Memory
|
|||
{
|
||||
int size8 = size & ~(8 - 1);
|
||||
|
||||
for (int offs = 0; offs < size8; offs += 8) memory.WriteInt64(position + offs, 0);
|
||||
for (int offs = 0; offs < size8; offs += 8)
|
||||
{
|
||||
memory.WriteInt64(position + offs, 0);
|
||||
}
|
||||
|
||||
for (int offs = size8; offs < size - size8; offs++) memory.WriteByte(position + offs, 0);
|
||||
for (int offs = size8; offs < size - size8; offs++)
|
||||
{
|
||||
memory.WriteByte(position + offs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe T Read<T>(AMemory memory, long position) where T : struct
|
||||
|
@ -46,7 +52,10 @@ namespace ChocolArm64.Memory
|
|||
{
|
||||
byte value = (byte)memory.ReadByte(position + offs);
|
||||
|
||||
if (value == 0) break;
|
||||
if (value == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ms.WriteByte(value);
|
||||
}
|
||||
|
|
|
@ -99,7 +99,10 @@ namespace ChocolArm64.State
|
|||
//do it after a given number of instructions has executed.
|
||||
_syncCount += bbWeight;
|
||||
|
||||
if (_syncCount >= MinInstForCheck) CheckInterrupt();
|
||||
if (_syncCount >= MinInstForCheck)
|
||||
{
|
||||
CheckInterrupt();
|
||||
}
|
||||
|
||||
return Running;
|
||||
}
|
||||
|
|
|
@ -47,14 +47,19 @@ namespace ChocolArm64.Translation
|
|||
else if (ilEmitter is AILOpCodeStore st)
|
||||
{
|
||||
if (AILEmitter.IsRegIndex(st.Index))
|
||||
{
|
||||
switch (st.IoType)
|
||||
{
|
||||
case AIoType.Flag: IntOutputs |= 1L << st.Index << 32; break;
|
||||
case AIoType.Int: IntOutputs |= 1L << st.Index; break;
|
||||
case AIoType.Vector: VecOutputs |= 1L << st.Index; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (st.IoType == AIoType.Fields) HasStateStore = true;
|
||||
if (st.IoType == AIoType.Fields)
|
||||
{
|
||||
HasStateStore = true;
|
||||
}
|
||||
}
|
||||
|
||||
IlEmitters.Add(ilEmitter);
|
||||
|
@ -62,7 +67,10 @@ namespace ChocolArm64.Translation
|
|||
|
||||
public void Emit(AILEmitter context)
|
||||
{
|
||||
foreach (IAilEmit ilEmitter in IlEmitters) ilEmitter.Emit(context);
|
||||
foreach (IAilEmit ilEmitter in IlEmitters)
|
||||
{
|
||||
ilEmitter.Emit(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,9 +35,15 @@ namespace ChocolArm64.Translation
|
|||
|
||||
AILBlock GetBlock(int index)
|
||||
{
|
||||
if (index < 0 || index >= _ilBlocks.Length) return null;
|
||||
if (index < 0 || index >= _ilBlocks.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_ilBlocks[index] == null) _ilBlocks[index] = new AILBlock();
|
||||
if (_ilBlocks[index] == null)
|
||||
{
|
||||
_ilBlocks[index] = new AILBlock();
|
||||
}
|
||||
|
||||
return _ilBlocks[index];
|
||||
}
|
||||
|
@ -65,7 +71,10 @@ namespace ChocolArm64.Translation
|
|||
InitSubroutine();
|
||||
InitLocals();
|
||||
|
||||
foreach (AILBlock ilBlock in _ilBlocks) ilBlock.Emit(this);
|
||||
foreach (AILBlock ilBlock in _ilBlocks)
|
||||
{
|
||||
ilBlock.Emit(this);
|
||||
}
|
||||
|
||||
return _subroutine;
|
||||
}
|
||||
|
@ -80,7 +89,10 @@ namespace ChocolArm64.Translation
|
|||
{
|
||||
long mask = 1L << bit;
|
||||
|
||||
if ((inputs & mask) != 0) Params.Add(GetRegFromBit(bit, baseType));
|
||||
if ((inputs & mask) != 0)
|
||||
{
|
||||
Params.Add(GetRegFromBit(bit, baseType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,7 +131,10 @@ namespace ChocolArm64.Translation
|
|||
|
||||
int typeIdx = fixedArgs.Length;
|
||||
|
||||
for (int index = 0; index < Params.Count; index++) output[typeIdx++] = GetFieldType(Params[index].Type);
|
||||
for (int index = 0; index < Params.Count; index++)
|
||||
{
|
||||
output[typeIdx++] = GetFieldType(Params[index].Type);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -158,11 +173,17 @@ namespace ChocolArm64.Translation
|
|||
public static ARegister GetRegFromBit(int bit, ARegisterType baseType)
|
||||
{
|
||||
if (bit < 32)
|
||||
{
|
||||
return new ARegister(bit, baseType);
|
||||
}
|
||||
else if (baseType == ARegisterType.Int)
|
||||
{
|
||||
return new ARegister(bit & 0x1f, ARegisterType.Flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(bit));
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsRegIndex(int index)
|
||||
|
|
|
@ -58,7 +58,10 @@ namespace ChocolArm64.Translation
|
|||
|
||||
_opcIndex = -1;
|
||||
|
||||
if (graph.Length == 0 || !AdvanceOpCode()) throw new ArgumentException(nameof(graph));
|
||||
if (graph.Length == 0 || !AdvanceOpCode())
|
||||
{
|
||||
throw new ArgumentException(nameof(graph));
|
||||
}
|
||||
}
|
||||
|
||||
public ATranslatedSub GetSubroutine()
|
||||
|
@ -70,7 +73,9 @@ namespace ChocolArm64.Translation
|
|||
{
|
||||
if (_opcIndex + 1 == CurrBlock.OpCodes.Count &&
|
||||
_blkIndex + 1 == _graph.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (++_opcIndex >= (CurrBlock?.OpCodes.Count ?? 0))
|
||||
{
|
||||
|
@ -123,21 +128,35 @@ namespace ChocolArm64.Translation
|
|||
|
||||
public bool TryOptEmitSubroutineCall()
|
||||
{
|
||||
if (CurrBlock.Next == null) return false;
|
||||
if (CurrBlock.Next == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CurrOp.Emitter != AInstEmit.Bl) return false;
|
||||
if (CurrOp.Emitter != AInstEmit.Bl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_cache.TryGetSubroutine(((AOpCodeBImmAl)CurrOp).Imm, out ATranslatedSub subroutine)) return false;
|
||||
if (!_cache.TryGetSubroutine(((AOpCodeBImmAl)CurrOp).Imm, out ATranslatedSub subroutine))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 0; index < ATranslatedSub.FixedArgTypes.Length; index++) EmitLdarg(index);
|
||||
for (int index = 0; index < ATranslatedSub.FixedArgTypes.Length; index++)
|
||||
{
|
||||
EmitLdarg(index);
|
||||
}
|
||||
|
||||
foreach (ARegister reg in subroutine.Params)
|
||||
{
|
||||
switch (reg.Type)
|
||||
{
|
||||
case ARegisterType.Flag: Ldloc(reg.Index, AIoType.Flag); break;
|
||||
case ARegisterType.Int: Ldloc(reg.Index, AIoType.Int); break;
|
||||
case ARegisterType.Vector: Ldloc(reg.Index, AIoType.Vector); break;
|
||||
}
|
||||
}
|
||||
|
||||
EmitCall(subroutine.Method);
|
||||
|
||||
|
@ -250,14 +269,20 @@ namespace ChocolArm64.Translation
|
|||
|
||||
if (sz64 == (intType == AIntType.UInt64 ||
|
||||
intType == AIntType.Int64))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sz64)
|
||||
{
|
||||
Emit(intType >= AIntType.Int8
|
||||
? OpCodes.Conv_I8
|
||||
: OpCodes.Conv_U8);
|
||||
}
|
||||
else
|
||||
{
|
||||
Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
}
|
||||
|
||||
public void EmitLsl(int amount)
|
||||
|
@ -345,17 +370,25 @@ namespace ChocolArm64.Translation
|
|||
public void EmitLdintzr(int index)
|
||||
{
|
||||
if (index != AThreadState.ZrIndex)
|
||||
{
|
||||
EmitLdint(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitLdc_I(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void EmitStintzr(int index)
|
||||
{
|
||||
if (index != AThreadState.ZrIndex)
|
||||
{
|
||||
EmitStint(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
Emit(OpCodes.Pop);
|
||||
}
|
||||
}
|
||||
|
||||
public void EmitLoadState(ABlock retBlk)
|
||||
|
@ -447,43 +480,70 @@ namespace ChocolArm64.Translation
|
|||
|
||||
public void EmitCallPropGet(Type objType, string propName)
|
||||
{
|
||||
if (objType == null) throw new ArgumentNullException(nameof(objType));
|
||||
if (objType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objType));
|
||||
}
|
||||
|
||||
if (propName == null) throw new ArgumentNullException(nameof(propName));
|
||||
if (propName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(propName));
|
||||
}
|
||||
|
||||
EmitCall(objType.GetMethod($"get_{propName}"));
|
||||
}
|
||||
|
||||
public void EmitCallPropSet(Type objType, string propName)
|
||||
{
|
||||
if (objType == null) throw new ArgumentNullException(nameof(objType));
|
||||
if (objType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objType));
|
||||
}
|
||||
|
||||
if (propName == null) throw new ArgumentNullException(nameof(propName));
|
||||
if (propName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(propName));
|
||||
}
|
||||
|
||||
EmitCall(objType.GetMethod($"set_{propName}"));
|
||||
}
|
||||
|
||||
public void EmitCall(Type objType, string mthdName)
|
||||
{
|
||||
if (objType == null) throw new ArgumentNullException(nameof(objType));
|
||||
if (objType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objType));
|
||||
}
|
||||
|
||||
if (mthdName == null) throw new ArgumentNullException(nameof(mthdName));
|
||||
if (mthdName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(mthdName));
|
||||
}
|
||||
|
||||
EmitCall(objType.GetMethod(mthdName));
|
||||
}
|
||||
|
||||
public void EmitPrivateCall(Type objType, string mthdName)
|
||||
{
|
||||
if (objType == null) throw new ArgumentNullException(nameof(objType));
|
||||
if (objType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objType));
|
||||
}
|
||||
|
||||
if (mthdName == null) throw new ArgumentNullException(nameof(mthdName));
|
||||
if (mthdName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(mthdName));
|
||||
}
|
||||
|
||||
EmitCall(objType.GetMethod(mthdName, BindingFlags.Instance | BindingFlags.NonPublic));
|
||||
}
|
||||
|
||||
public void EmitCall(MethodInfo mthdInfo)
|
||||
{
|
||||
if (mthdInfo == null) throw new ArgumentNullException(nameof(mthdInfo));
|
||||
if (mthdInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(mthdInfo));
|
||||
}
|
||||
|
||||
_ilBlock.Add(new AILOpCodeCall(mthdInfo));
|
||||
}
|
||||
|
@ -491,9 +551,13 @@ namespace ChocolArm64.Translation
|
|||
public void EmitLdc_I(long value)
|
||||
{
|
||||
if (CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
EmitLdc_I4((int)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitLdc_I8(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void EmitLdc_I4(int value)
|
||||
|
@ -527,7 +591,10 @@ namespace ChocolArm64.Translation
|
|||
Emit(OpCodes.Dup);
|
||||
Emit(OpCodes.Ldc_I4_0);
|
||||
|
||||
if (CurrOp.RegisterSize != ARegisterSize.Int32) Emit(OpCodes.Conv_I8);
|
||||
if (CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
Emit(OpCodes.Conv_I8);
|
||||
}
|
||||
|
||||
Emit(ilCmpOp);
|
||||
|
||||
|
|
|
@ -67,7 +67,9 @@ namespace ChocolArm64.Translation
|
|||
|
||||
if (registerType == ARegisterType.Int &&
|
||||
RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
context.Generator.Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -65,7 +65,9 @@ namespace ChocolArm64.Translation
|
|||
|
||||
if (registerType == ARegisterType.Int &&
|
||||
RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
context.Generator.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
context.Generator.EmitStloc(context.GetLocalIndex(reg));
|
||||
}
|
||||
|
|
|
@ -24,16 +24,25 @@ namespace ChocolArm64.Translation
|
|||
|
||||
public void Set(AILBlock root, long inputs, long outputs)
|
||||
{
|
||||
if (!_allInputs.TryAdd(root, inputs)) _allInputs[root] |= inputs;
|
||||
if (!_allInputs.TryAdd(root, inputs))
|
||||
{
|
||||
_allInputs[root] |= inputs;
|
||||
}
|
||||
|
||||
if (!_cmnOutputs.TryAdd(root, outputs)) _cmnOutputs[root] &= outputs;
|
||||
if (!_cmnOutputs.TryAdd(root, outputs))
|
||||
{
|
||||
_cmnOutputs[root] &= outputs;
|
||||
}
|
||||
|
||||
_allOutputs |= outputs;
|
||||
}
|
||||
|
||||
public long GetInputs(AILBlock root)
|
||||
{
|
||||
if (_allInputs.TryGetValue(root, out long inputs)) return inputs | (_allOutputs & ~_cmnOutputs[root]);
|
||||
if (_allInputs.TryGetValue(root, out long inputs))
|
||||
{
|
||||
return inputs | (_allOutputs & ~_cmnOutputs[root]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -67,9 +76,13 @@ namespace ChocolArm64.Translation
|
|||
|
||||
if (graph.Length > 1 &&
|
||||
graph.Length < MaxOptGraphLength)
|
||||
{
|
||||
InitializeOptimal(graph, root);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeFast(graph);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeOptimal(AILBlock[] graph, AILBlock root)
|
||||
|
@ -117,9 +130,15 @@ namespace ChocolArm64.Translation
|
|||
if (current.Block.Next == null &&
|
||||
current.Block.Branch == null || current.Block.HasStateStore)
|
||||
{
|
||||
if (!_intPaths.TryGetValue(current.Block, out PathIo intPath)) _intPaths.Add(current.Block, intPath = new PathIo());
|
||||
if (!_intPaths.TryGetValue(current.Block, out PathIo intPath))
|
||||
{
|
||||
_intPaths.Add(current.Block, intPath = new PathIo());
|
||||
}
|
||||
|
||||
if (!_vecPaths.TryGetValue(current.Block, out PathIo vecPath)) _vecPaths.Add(current.Block, vecPath = new PathIo());
|
||||
if (!_vecPaths.TryGetValue(current.Block, out PathIo vecPath))
|
||||
{
|
||||
_vecPaths.Add(current.Block, vecPath = new PathIo());
|
||||
}
|
||||
|
||||
intPath.Set(current.Entry, current.IntInputs, current.IntOutputs);
|
||||
vecPath.Set(current.Entry, current.VecInputs, current.VecOutputs);
|
||||
|
@ -145,9 +164,15 @@ namespace ChocolArm64.Translation
|
|||
Enqueue(blkIo);
|
||||
}
|
||||
|
||||
if (current.Block.Next != null) EnqueueFromCurrent(current.Block.Next, current.Block.HasStateStore);
|
||||
if (current.Block.Next != null)
|
||||
{
|
||||
EnqueueFromCurrent(current.Block.Next, current.Block.HasStateStore);
|
||||
}
|
||||
|
||||
if (current.Block.Branch != null) EnqueueFromCurrent(current.Block.Branch, false);
|
||||
if (current.Block.Branch != null)
|
||||
{
|
||||
EnqueueFromCurrent(current.Block.Branch, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +222,10 @@ namespace ChocolArm64.Translation
|
|||
{
|
||||
long inputs = 0;
|
||||
|
||||
foreach (PathIo path in values) inputs |= path.GetInputs(root);
|
||||
foreach (PathIo path in values)
|
||||
{
|
||||
inputs |= path.GetInputs(root);
|
||||
}
|
||||
|
||||
return inputs;
|
||||
}
|
||||
|
|
|
@ -35,11 +35,18 @@ namespace ChocolArm64
|
|||
|
||||
default:
|
||||
if ((uint)index <= byte.MaxValue)
|
||||
{
|
||||
generator.Emit(OpCodes.Ldarg_S, (byte)index);
|
||||
}
|
||||
else if ((uint)index < ushort.MaxValue)
|
||||
{
|
||||
generator.Emit(OpCodes.Ldarg, (short)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -47,11 +54,17 @@ namespace ChocolArm64
|
|||
public static void EmitStarg(this ILGenerator generator, int index)
|
||||
{
|
||||
if ((uint)index <= byte.MaxValue)
|
||||
{
|
||||
generator.Emit(OpCodes.Starg_S, (byte)index);
|
||||
}
|
||||
else if ((uint)index < ushort.MaxValue)
|
||||
{
|
||||
generator.Emit(OpCodes.Starg, (short)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitLdloc(this ILGenerator generator, int index)
|
||||
|
@ -65,11 +78,18 @@ namespace ChocolArm64
|
|||
|
||||
default:
|
||||
if ((uint)index <= byte.MaxValue)
|
||||
{
|
||||
generator.Emit(OpCodes.Ldloc_S, (byte)index);
|
||||
}
|
||||
else if ((uint)index < ushort.MaxValue)
|
||||
{
|
||||
generator.Emit(OpCodes.Ldloc, (short)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -85,18 +105,28 @@ namespace ChocolArm64
|
|||
|
||||
default:
|
||||
if ((uint)index <= byte.MaxValue)
|
||||
{
|
||||
generator.Emit(OpCodes.Stloc_S, (byte)index);
|
||||
}
|
||||
else if ((uint)index < ushort.MaxValue)
|
||||
{
|
||||
generator.Emit(OpCodes.Stloc, (short)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitLdargSeq(this ILGenerator generator, int count)
|
||||
{
|
||||
for (int index = 0; index < count; index++) generator.EmitLdarg(index);
|
||||
for (int index = 0; index < count; index++)
|
||||
{
|
||||
generator.EmitLdarg(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,10 @@ namespace Ryujinx.Audio.Adpcm
|
|||
|
||||
int frameSamples = SamplesPerFrame;
|
||||
|
||||
if (frameSamples > samples) frameSamples = samples;
|
||||
if (frameSamples > samples)
|
||||
{
|
||||
frameSamples = samples;
|
||||
}
|
||||
|
||||
int value = 0;
|
||||
|
||||
|
|
|
@ -5,10 +5,14 @@ namespace Ryujinx.Audio.Adpcm
|
|||
public static short Saturate(int value)
|
||||
{
|
||||
if (value > short.MaxValue)
|
||||
{
|
||||
value = short.MaxValue;
|
||||
}
|
||||
|
||||
if (value < short.MinValue)
|
||||
{
|
||||
value = short.MinValue;
|
||||
}
|
||||
|
||||
return (short)value;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,12 @@ namespace Ryujinx.Audio.OpenAL
|
|||
public bool ContainsBuffer(long tag)
|
||||
{
|
||||
foreach (long queuedTag in _queuedTagsQueue)
|
||||
if (queuedTag == tag) return true;
|
||||
{
|
||||
if (queuedTag == tag)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -67,11 +72,17 @@ namespace Ryujinx.Audio.OpenAL
|
|||
|
||||
releasedCount += _releasedTagsQueue.Count;
|
||||
|
||||
if (count > releasedCount) count = releasedCount;
|
||||
if (count > releasedCount)
|
||||
{
|
||||
count = releasedCount;
|
||||
}
|
||||
|
||||
List<long> tags = new List<long>();
|
||||
|
||||
while (count-- > 0 && _releasedTagsQueue.TryDequeue(out long tag)) tags.Add(tag);
|
||||
while (count-- > 0 && _releasedTagsQueue.TryDequeue(out long tag))
|
||||
{
|
||||
tags.Add(tag);
|
||||
}
|
||||
|
||||
while (count-- > 0 && _queuedTagsQueue.TryDequeue(out long tag))
|
||||
{
|
||||
|
@ -85,7 +96,10 @@ namespace Ryujinx.Audio.OpenAL
|
|||
|
||||
public int AppendBuffer(long tag)
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException(nameof(Track));
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(Track));
|
||||
}
|
||||
|
||||
int id = AL.GenBuffer();
|
||||
|
||||
|
@ -135,7 +149,10 @@ namespace Ryujinx.Audio.OpenAL
|
|||
|
||||
AL.DeleteSource(SourceId);
|
||||
|
||||
foreach (int id in _buffers.Values) AL.DeleteBuffer(id);
|
||||
foreach (int id in _buffers.Values)
|
||||
{
|
||||
AL.DeleteBuffer(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,17 +181,22 @@ namespace Ryujinx.Audio.OpenAL
|
|||
do
|
||||
{
|
||||
foreach (Track td in _tracks.Values)
|
||||
{
|
||||
lock (td)
|
||||
{
|
||||
td.CallReleaseCallbackIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
//If it's not slept it will waste cycles.
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
while (_keepPolling);
|
||||
|
||||
foreach (Track td in _tracks.Values) td.Dispose();
|
||||
foreach (Track td in _tracks.Values)
|
||||
{
|
||||
td.Dispose();
|
||||
}
|
||||
|
||||
_tracks.Clear();
|
||||
}
|
||||
|
@ -184,7 +206,12 @@ namespace Ryujinx.Audio.OpenAL
|
|||
Track td = new Track(sampleRate, GetAlFormat(channels), callback);
|
||||
|
||||
for (int id = 0; id < MaxTracks; id++)
|
||||
if (_tracks.TryAdd(id, td)) return id;
|
||||
{
|
||||
if (_tracks.TryAdd(id, td))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -204,19 +231,23 @@ namespace Ryujinx.Audio.OpenAL
|
|||
public void CloseTrack(int track)
|
||||
{
|
||||
if (_tracks.TryRemove(track, out Track td))
|
||||
{
|
||||
lock (td)
|
||||
{
|
||||
td.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsBuffer(int track, long tag)
|
||||
{
|
||||
if (_tracks.TryGetValue(track, out Track td))
|
||||
{
|
||||
lock (td)
|
||||
{
|
||||
return td.ContainsBuffer(tag);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -224,10 +255,12 @@ namespace Ryujinx.Audio.OpenAL
|
|||
public long[] GetReleasedBuffers(int track, int maxCount)
|
||||
{
|
||||
if (_tracks.TryGetValue(track, out Track td))
|
||||
{
|
||||
lock (td)
|
||||
{
|
||||
return td.GetReleasedBuffers(maxCount);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -235,6 +268,7 @@ namespace Ryujinx.Audio.OpenAL
|
|||
public void AppendBuffer<T>(int track, long tag, T[] buffer) where T : struct
|
||||
{
|
||||
if (_tracks.TryGetValue(track, out Track td))
|
||||
{
|
||||
lock (td)
|
||||
{
|
||||
int bufferId = td.AppendBuffer(tag);
|
||||
|
@ -247,17 +281,20 @@ namespace Ryujinx.Audio.OpenAL
|
|||
|
||||
StartPlaybackIfNeeded(td);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Start(int track)
|
||||
{
|
||||
if (_tracks.TryGetValue(track, out Track td))
|
||||
{
|
||||
lock (td)
|
||||
{
|
||||
td.State = PlaybackState.Playing;
|
||||
|
||||
StartPlaybackIfNeeded(td);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StartPlaybackIfNeeded(Track td)
|
||||
|
@ -266,23 +303,31 @@ namespace Ryujinx.Audio.OpenAL
|
|||
|
||||
ALSourceState state = (ALSourceState)stateInt;
|
||||
|
||||
if (state != ALSourceState.Playing && td.State == PlaybackState.Playing) AL.SourcePlay(td.SourceId);
|
||||
if (state != ALSourceState.Playing && td.State == PlaybackState.Playing)
|
||||
{
|
||||
AL.SourcePlay(td.SourceId);
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop(int track)
|
||||
{
|
||||
if (_tracks.TryGetValue(track, out Track td))
|
||||
{
|
||||
lock (td)
|
||||
{
|
||||
td.State = PlaybackState.Stopped;
|
||||
|
||||
AL.SourceStop(td.SourceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PlaybackState GetState(int track)
|
||||
{
|
||||
if (_tracks.TryGetValue(track, out Track td)) return td.State;
|
||||
if (_tracks.TryGetValue(track, out Track td))
|
||||
{
|
||||
return td.State;
|
||||
}
|
||||
|
||||
return PlaybackState.Stopped;
|
||||
}
|
||||
|
@ -294,7 +339,10 @@ namespace Ryujinx.Audio.OpenAL
|
|||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing) _keepPolling = false;
|
||||
if (disposing)
|
||||
{
|
||||
_keepPolling = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,10 @@ namespace Ryujinx.Common.Logging
|
|||
_enabledLevels[(int)LogLevel.Warning] = true;
|
||||
_enabledLevels[(int)LogLevel.Error] = true;
|
||||
|
||||
for (int index = 0; index < _enabledClasses.Length; index++) _enabledClasses[index] = true;
|
||||
for (int index = 0; index < _enabledClasses.Length; index++)
|
||||
{
|
||||
_enabledClasses[index] = true;
|
||||
}
|
||||
|
||||
_time = new Stopwatch();
|
||||
|
||||
|
@ -67,7 +70,10 @@ namespace Ryujinx.Common.Logging
|
|||
|
||||
private static void Print(LogLevel level, LogClass Class, string message)
|
||||
{
|
||||
if (_enabledLevels[(int)level] && _enabledClasses[(int)Class]) Updated?.Invoke(null, new LogEventArgs(level, _time.Elapsed, message));
|
||||
if (_enabledLevels[(int)level] && _enabledClasses[(int)Class])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(level, _time.Elapsed, message));
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetFormattedMessage(LogClass Class, string message, string caller)
|
||||
|
|
|
@ -47,11 +47,15 @@ namespace Ryujinx.Graphics.Gal
|
|||
{
|
||||
if (ImageUtils.GetBytesPerPixel(Format) !=
|
||||
ImageUtils.GetBytesPerPixel(image.Format))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ImageUtils.GetAlignedWidth(this) !=
|
||||
ImageUtils.GetAlignedWidth(image))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Height == image.Height;
|
||||
}
|
||||
|
|
|
@ -84,7 +84,10 @@
|
|||
{
|
||||
ConstBufferKeys = new long[Stages][];
|
||||
|
||||
for (int stage = 0; stage < Stages; stage++) ConstBufferKeys[stage] = new long[ConstBuffersPerStage];
|
||||
for (int stage = 0; stage < Stages; stage++)
|
||||
{
|
||||
ConstBufferKeys[stage] = new long[ConstBuffersPerStage];
|
||||
}
|
||||
|
||||
ColorMasks = new ColorMaskRgba[RenderTargetsCount];
|
||||
}
|
||||
|
|
|
@ -42,7 +42,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public OGLCachedResource(DeleteValue deleteValueCallback)
|
||||
{
|
||||
if (deleteValueCallback == null) throw new ArgumentNullException(nameof(deleteValueCallback));
|
||||
if (deleteValueCallback == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(deleteValueCallback));
|
||||
}
|
||||
|
||||
_deleteValueCallback = deleteValueCallback;
|
||||
|
||||
|
@ -62,14 +65,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
_locked = false;
|
||||
|
||||
while (_deletePending.TryDequeue(out T value)) _deleteValueCallback(value);
|
||||
while (_deletePending.TryDequeue(out T value))
|
||||
{
|
||||
_deleteValueCallback(value);
|
||||
}
|
||||
|
||||
ClearCacheIfNeeded();
|
||||
}
|
||||
|
||||
public void AddOrUpdate(long key, T value, long size)
|
||||
{
|
||||
if (!_locked) ClearCacheIfNeeded();
|
||||
if (!_locked)
|
||||
{
|
||||
ClearCacheIfNeeded();
|
||||
}
|
||||
|
||||
LinkedListNode<long> node = _sortedCache.AddLast(key);
|
||||
|
||||
|
@ -78,9 +87,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
if (_cache.TryGetValue(key, out CacheBucket bucket))
|
||||
{
|
||||
if (_locked)
|
||||
{
|
||||
_deletePending.Enqueue(bucket.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_deleteValueCallback(bucket.Value);
|
||||
}
|
||||
|
||||
_sortedCache.Remove(bucket.Node);
|
||||
|
||||
|
@ -136,13 +149,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
LinkedListNode<long> node = _sortedCache.First;
|
||||
|
||||
if (node == null) break;
|
||||
if (node == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CacheBucket bucket = _cache[node.Value];
|
||||
|
||||
int timeDelta = RingDelta(bucket.Timestamp, timestamp);
|
||||
|
||||
if ((uint)timeDelta <= (uint)MaxTimeDelta) break;
|
||||
if ((uint)timeDelta <= (uint)MaxTimeDelta)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
_sortedCache.Remove(node);
|
||||
|
||||
|
@ -155,9 +174,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
private int RingDelta(int old, int New)
|
||||
{
|
||||
if ((uint)New < (uint)old)
|
||||
{
|
||||
return New + ~old + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return New - old;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void SetData(long key, long size, IntPtr hostAddress)
|
||||
{
|
||||
if (_cache.TryGetValue(key, out OGLStreamBuffer buffer)) buffer.SetData(size, hostAddress);
|
||||
if (_cache.TryGetValue(key, out OGLStreamBuffer buffer))
|
||||
{
|
||||
buffer.SetData(size, hostAddress);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetUbo(long key, out int uboHandle)
|
||||
|
|
|
@ -50,7 +50,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
//Looks like the GPU can take it's own values (described in GalComparisonOp) and OpenGL values alike
|
||||
if ((int)func >= (int)DepthFunction.Never &&
|
||||
(int)func <= (int)DepthFunction.Always)
|
||||
{
|
||||
return (DepthFunction)func;
|
||||
}
|
||||
|
||||
switch (func)
|
||||
{
|
||||
|
@ -229,19 +231,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
|
||||
if (OGLExtension.TextureMirrorClamp)
|
||||
{
|
||||
switch (wrap)
|
||||
{
|
||||
case GalTextureWrap.MirrorClampToEdge: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToEdgeExt;
|
||||
case GalTextureWrap.MirrorClampToBorder: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToBorderExt;
|
||||
case GalTextureWrap.MirrorClamp: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampExt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (wrap)
|
||||
{
|
||||
case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
|
||||
case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder;
|
||||
case GalTextureWrap.MirrorClamp: return TextureWrapMode.Clamp;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(wrap) + " \"" + wrap + "\" is not valid!");
|
||||
}
|
||||
|
|
|
@ -18,7 +18,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
int numExtensions = GL.GetInteger(GetPName.NumExtensions);
|
||||
|
||||
for (int extension = 0; extension < numExtensions; extension++)
|
||||
if (GL.GetString(StringNameIndexed.Extensions, extension) == name) return true;
|
||||
{
|
||||
if (GL.GetString(StringNameIndexed.Extensions, extension) == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
PrimitiveRestartIndex = 0
|
||||
};
|
||||
|
||||
for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++) _old.ColorMasks[index] = ColorMaskRgba.Default;
|
||||
for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
|
||||
{
|
||||
_old.ColorMasks[index] = ColorMaskRgba.Default;
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind(GalPipelineState New)
|
||||
|
@ -144,9 +147,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
BindVertexLayout(New);
|
||||
|
||||
if (New.FramebufferSrgb != _old.FramebufferSrgb) Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb);
|
||||
if (New.FramebufferSrgb != _old.FramebufferSrgb)
|
||||
{
|
||||
Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb);
|
||||
}
|
||||
|
||||
if (New.FlipX != _old.FlipX || New.FlipY != _old.FlipY || New.Instance != _old.Instance) _shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
||||
if (New.FlipX != _old.FlipX || New.FlipY != _old.FlipY || New.Instance != _old.Instance)
|
||||
{
|
||||
_shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
||||
}
|
||||
|
||||
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
||||
|
||||
|
@ -168,65 +177,101 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
// }
|
||||
//}
|
||||
|
||||
if (New.DepthTestEnabled != _old.DepthTestEnabled) Enable(EnableCap.DepthTest, New.DepthTestEnabled);
|
||||
if (New.DepthTestEnabled != _old.DepthTestEnabled)
|
||||
{
|
||||
Enable(EnableCap.DepthTest, New.DepthTestEnabled);
|
||||
}
|
||||
|
||||
if (New.DepthWriteEnabled != _old.DepthWriteEnabled) GL.DepthMask(New.DepthWriteEnabled);
|
||||
if (New.DepthWriteEnabled != _old.DepthWriteEnabled)
|
||||
{
|
||||
GL.DepthMask(New.DepthWriteEnabled);
|
||||
}
|
||||
|
||||
if (New.DepthTestEnabled)
|
||||
if (New.DepthFunc != _old.DepthFunc) GL.DepthFunc(OGLEnumConverter.GetDepthFunc(New.DepthFunc));
|
||||
{
|
||||
if (New.DepthFunc != _old.DepthFunc)
|
||||
{
|
||||
GL.DepthFunc(OGLEnumConverter.GetDepthFunc(New.DepthFunc));
|
||||
}
|
||||
}
|
||||
|
||||
if (New.DepthRangeNear != _old.DepthRangeNear ||
|
||||
New.DepthRangeFar != _old.DepthRangeFar)
|
||||
{
|
||||
GL.DepthRange(New.DepthRangeNear, New.DepthRangeFar);
|
||||
}
|
||||
|
||||
if (New.StencilTestEnabled != _old.StencilTestEnabled) Enable(EnableCap.StencilTest, New.StencilTestEnabled);
|
||||
if (New.StencilTestEnabled != _old.StencilTestEnabled)
|
||||
{
|
||||
Enable(EnableCap.StencilTest, New.StencilTestEnabled);
|
||||
}
|
||||
|
||||
if (New.StencilTwoSideEnabled != _old.StencilTwoSideEnabled) Enable((EnableCap)All.StencilTestTwoSideExt, New.StencilTwoSideEnabled);
|
||||
if (New.StencilTwoSideEnabled != _old.StencilTwoSideEnabled)
|
||||
{
|
||||
Enable((EnableCap)All.StencilTestTwoSideExt, New.StencilTwoSideEnabled);
|
||||
}
|
||||
|
||||
if (New.StencilTestEnabled)
|
||||
{
|
||||
if (New.StencilBackFuncFunc != _old.StencilBackFuncFunc ||
|
||||
New.StencilBackFuncRef != _old.StencilBackFuncRef ||
|
||||
New.StencilBackFuncMask != _old.StencilBackFuncMask)
|
||||
{
|
||||
GL.StencilFuncSeparate(
|
||||
StencilFace.Back,
|
||||
OGLEnumConverter.GetStencilFunc(New.StencilBackFuncFunc),
|
||||
New.StencilBackFuncRef,
|
||||
New.StencilBackFuncMask);
|
||||
}
|
||||
|
||||
if (New.StencilBackOpFail != _old.StencilBackOpFail ||
|
||||
New.StencilBackOpZFail != _old.StencilBackOpZFail ||
|
||||
New.StencilBackOpZPass != _old.StencilBackOpZPass)
|
||||
{
|
||||
GL.StencilOpSeparate(
|
||||
StencilFace.Back,
|
||||
OGLEnumConverter.GetStencilOp(New.StencilBackOpFail),
|
||||
OGLEnumConverter.GetStencilOp(New.StencilBackOpZFail),
|
||||
OGLEnumConverter.GetStencilOp(New.StencilBackOpZPass));
|
||||
}
|
||||
|
||||
if (New.StencilBackMask != _old.StencilBackMask) GL.StencilMaskSeparate(StencilFace.Back, New.StencilBackMask);
|
||||
if (New.StencilBackMask != _old.StencilBackMask)
|
||||
{
|
||||
GL.StencilMaskSeparate(StencilFace.Back, New.StencilBackMask);
|
||||
}
|
||||
|
||||
if (New.StencilFrontFuncFunc != _old.StencilFrontFuncFunc ||
|
||||
New.StencilFrontFuncRef != _old.StencilFrontFuncRef ||
|
||||
New.StencilFrontFuncMask != _old.StencilFrontFuncMask)
|
||||
{
|
||||
GL.StencilFuncSeparate(
|
||||
StencilFace.Front,
|
||||
OGLEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc),
|
||||
New.StencilFrontFuncRef,
|
||||
New.StencilFrontFuncMask);
|
||||
}
|
||||
|
||||
if (New.StencilFrontOpFail != _old.StencilFrontOpFail ||
|
||||
New.StencilFrontOpZFail != _old.StencilFrontOpZFail ||
|
||||
New.StencilFrontOpZPass != _old.StencilFrontOpZPass)
|
||||
{
|
||||
GL.StencilOpSeparate(
|
||||
StencilFace.Front,
|
||||
OGLEnumConverter.GetStencilOp(New.StencilFrontOpFail),
|
||||
OGLEnumConverter.GetStencilOp(New.StencilFrontOpZFail),
|
||||
OGLEnumConverter.GetStencilOp(New.StencilFrontOpZPass));
|
||||
}
|
||||
|
||||
if (New.StencilFrontMask != _old.StencilFrontMask) GL.StencilMaskSeparate(StencilFace.Front, New.StencilFrontMask);
|
||||
if (New.StencilFrontMask != _old.StencilFrontMask)
|
||||
{
|
||||
GL.StencilMaskSeparate(StencilFace.Front, New.StencilFrontMask);
|
||||
}
|
||||
}
|
||||
|
||||
if (New.BlendEnabled != _old.BlendEnabled) Enable(EnableCap.Blend, New.BlendEnabled);
|
||||
if (New.BlendEnabled != _old.BlendEnabled)
|
||||
{
|
||||
Enable(EnableCap.Blend, New.BlendEnabled);
|
||||
}
|
||||
|
||||
if (New.BlendEnabled)
|
||||
{
|
||||
|
@ -234,57 +279,80 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
if (New.BlendEquationRgb != _old.BlendEquationRgb ||
|
||||
New.BlendEquationAlpha != _old.BlendEquationAlpha)
|
||||
{
|
||||
GL.BlendEquationSeparate(
|
||||
OGLEnumConverter.GetBlendEquation(New.BlendEquationRgb),
|
||||
OGLEnumConverter.GetBlendEquation(New.BlendEquationAlpha));
|
||||
}
|
||||
|
||||
if (New.BlendFuncSrcRgb != _old.BlendFuncSrcRgb ||
|
||||
New.BlendFuncDstRgb != _old.BlendFuncDstRgb ||
|
||||
New.BlendFuncSrcAlpha != _old.BlendFuncSrcAlpha ||
|
||||
New.BlendFuncDstAlpha != _old.BlendFuncDstAlpha)
|
||||
{
|
||||
GL.BlendFuncSeparate(
|
||||
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.BlendFuncSrcRgb),
|
||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.BlendFuncDstRgb),
|
||||
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.BlendFuncSrcAlpha),
|
||||
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.BlendFuncDstAlpha));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (New.BlendEquationRgb != _old.BlendEquationRgb) GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.BlendEquationRgb));
|
||||
if (New.BlendEquationRgb != _old.BlendEquationRgb)
|
||||
{
|
||||
GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.BlendEquationRgb));
|
||||
}
|
||||
|
||||
if (New.BlendFuncSrcRgb != _old.BlendFuncSrcRgb ||
|
||||
New.BlendFuncDstRgb != _old.BlendFuncDstRgb)
|
||||
{
|
||||
GL.BlendFunc(
|
||||
OGLEnumConverter.GetBlendFactor(New.BlendFuncSrcRgb),
|
||||
OGLEnumConverter.GetBlendFactor(New.BlendFuncDstRgb));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (New.ColorMaskCommon)
|
||||
{
|
||||
if (New.ColorMaskCommon != _old.ColorMaskCommon || !New.ColorMasks[0].Equals(_old.ColorMasks[0]))
|
||||
{
|
||||
GL.ColorMask(
|
||||
New.ColorMasks[0].Red,
|
||||
New.ColorMasks[0].Green,
|
||||
New.ColorMasks[0].Blue,
|
||||
New.ColorMasks[0].Alpha);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
|
||||
{
|
||||
if (!New.ColorMasks[index].Equals(_old.ColorMasks[index]))
|
||||
{
|
||||
GL.ColorMask(
|
||||
index,
|
||||
New.ColorMasks[index].Red,
|
||||
New.ColorMasks[index].Green,
|
||||
New.ColorMasks[index].Blue,
|
||||
New.ColorMasks[index].Alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (New.PrimitiveRestartEnabled != _old.PrimitiveRestartEnabled) Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
|
||||
if (New.PrimitiveRestartEnabled != _old.PrimitiveRestartEnabled)
|
||||
{
|
||||
Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
|
||||
}
|
||||
|
||||
if (New.PrimitiveRestartEnabled)
|
||||
if (New.PrimitiveRestartIndex != _old.PrimitiveRestartIndex) GL.PrimitiveRestartIndex(New.PrimitiveRestartIndex);
|
||||
{
|
||||
if (New.PrimitiveRestartIndex != _old.PrimitiveRestartIndex)
|
||||
{
|
||||
GL.PrimitiveRestartIndex(New.PrimitiveRestartIndex);
|
||||
}
|
||||
}
|
||||
|
||||
_old = New;
|
||||
}
|
||||
|
@ -296,14 +364,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
void BindIfNotNull(OGLShaderStage stage)
|
||||
{
|
||||
if (stage != null)
|
||||
{
|
||||
foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage)
|
||||
{
|
||||
long key = New.ConstBufferKeys[(int)stage.Type][declInfo.Cbuf];
|
||||
|
||||
if (key != 0 && _buffer.TryGetUbo(key, out int uboHandle)) GL.BindBufferBase(BufferRangeTarget.UniformBuffer, freeBinding, uboHandle);
|
||||
if (key != 0 && _buffer.TryGetUbo(key, out int uboHandle))
|
||||
{
|
||||
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, freeBinding, uboHandle);
|
||||
}
|
||||
|
||||
freeBinding++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BindIfNotNull(_shader.Current.Vertex);
|
||||
|
@ -317,7 +390,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
foreach (GalVertexBinding binding in New.VertexBindings)
|
||||
{
|
||||
if (!binding.Enabled || !_rasterizer.TryGetVbo(binding.VboKey, out int vboHandle)) continue;
|
||||
if (!binding.Enabled || !_rasterizer.TryGetVbo(binding.VboKey, out int vboHandle))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_vaoHandle == 0)
|
||||
{
|
||||
|
@ -331,7 +407,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
foreach (GalVertexAttrib attrib in binding.Attribs)
|
||||
{
|
||||
//Skip uninitialized attributes.
|
||||
if (attrib.Size == 0) continue;
|
||||
if (attrib.Size == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, vboHandle);
|
||||
|
||||
|
@ -353,12 +432,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
else
|
||||
{
|
||||
if (unsigned)
|
||||
{
|
||||
type = GetType(_unsignedAttribTypes, attrib);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = GetType(_signedAttribTypes, attrib);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_attribElements.TryGetValue(attrib.Size, out int size)) throw new InvalidOperationException("Invalid attribute size \"" + attrib.Size + "\"!");
|
||||
if (!_attribElements.TryGetValue(attrib.Size, out int size))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid attribute size \"" + attrib.Size + "\"!");
|
||||
}
|
||||
|
||||
int offset = attrib.Offset;
|
||||
|
||||
|
@ -388,16 +474,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
|
||||
if (binding.Instanced && binding.Divisor != 0)
|
||||
{
|
||||
GL.VertexAttribDivisor(attrib.Index, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.VertexAttribDivisor(attrib.Index, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static VertexAttribPointerType GetType(Dictionary<GalVertexAttribSize, VertexAttribPointerType> dict, GalVertexAttrib attrib)
|
||||
{
|
||||
if (!dict.TryGetValue(attrib.Size, out VertexAttribPointerType type)) ThrowUnsupportedAttrib(attrib);
|
||||
if (!dict.TryGetValue(attrib.Size, out VertexAttribPointerType type))
|
||||
{
|
||||
ThrowUnsupportedAttrib(attrib);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
@ -406,9 +499,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
if (attrib.Size == GalVertexAttribSize._10_10_10_2 ||
|
||||
attrib.Size == GalVertexAttribSize._11_11_10)
|
||||
{
|
||||
ThrowUnsupportedAttrib(attrib);
|
||||
}
|
||||
|
||||
if (attrib.Type == GalVertexAttribType.Unorm)
|
||||
{
|
||||
switch (attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
|
@ -432,7 +528,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.VertexAttrib4N((uint)attrib.Index, (uint*)attrib.Pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (attrib.Type == GalVertexAttribType.Snorm)
|
||||
{
|
||||
switch (attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
|
@ -456,7 +554,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.VertexAttrib4N((uint)attrib.Index, (int*)attrib.Pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (attrib.Type == GalVertexAttribType.Uint)
|
||||
{
|
||||
switch (attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
|
@ -480,7 +580,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.VertexAttribI4((uint)attrib.Index, (uint*)attrib.Pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (attrib.Type == GalVertexAttribType.Sint)
|
||||
{
|
||||
switch (attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
|
@ -504,7 +606,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.VertexAttribI4((uint)attrib.Index, (int*)attrib.Pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (attrib.Type == GalVertexAttribType.Float)
|
||||
{
|
||||
switch (attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._32:
|
||||
|
@ -516,6 +620,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
default: ThrowUnsupportedAttrib(attrib); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ThrowUnsupportedAttrib(GalVertexAttrib attrib)
|
||||
|
@ -526,9 +631,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
private void Enable(EnableCap cap, bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
GL.Enable(cap);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.Disable(cap);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetDepthMask()
|
||||
|
|
|
@ -64,9 +64,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.ColorMask(attachment, true, true, true, true);
|
||||
GL.DepthMask(true);
|
||||
|
||||
if (flags.HasFlag(GalClearBufferFlags.Depth)) GL.ClearBuffer(ClearBuffer.Depth, 0, ref depth);
|
||||
if (flags.HasFlag(GalClearBufferFlags.Depth))
|
||||
{
|
||||
GL.ClearBuffer(ClearBuffer.Depth, 0, ref depth);
|
||||
}
|
||||
|
||||
if (flags.HasFlag(GalClearBufferFlags.Stencil)) GL.ClearBuffer(ClearBuffer.Stencil, 0, ref stencil);
|
||||
if (flags.HasFlag(GalClearBufferFlags.Stencil))
|
||||
{
|
||||
GL.ClearBuffer(ClearBuffer.Stencil, 0, ref stencil);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsVboCached(long key, long dataSize)
|
||||
|
@ -126,17 +132,26 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void DrawArrays(int first, int count, GalPrimitiveType primType)
|
||||
{
|
||||
if (count == 0) return;
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (primType == GalPrimitiveType.Quads)
|
||||
{
|
||||
for (int offset = 0; offset < count; offset += 4) GL.DrawArrays(PrimitiveType.TriangleFan, first + offset, 4);
|
||||
for (int offset = 0; offset < count; offset += 4)
|
||||
{
|
||||
GL.DrawArrays(PrimitiveType.TriangleFan, first + offset, 4);
|
||||
}
|
||||
}
|
||||
else if (primType == GalPrimitiveType.QuadStrip)
|
||||
{
|
||||
GL.DrawArrays(PrimitiveType.TriangleFan, first, 4);
|
||||
|
||||
for (int offset = 2; offset < count; offset += 2) GL.DrawArrays(PrimitiveType.TriangleFan, first + offset, 4);
|
||||
for (int offset = 2; offset < count; offset += 2)
|
||||
{
|
||||
GL.DrawArrays(PrimitiveType.TriangleFan, first + offset, 4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -146,7 +161,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void DrawElements(long iboKey, int first, int vertexBase, GalPrimitiveType primType)
|
||||
{
|
||||
if (!_iboCache.TryGetValue(iboKey, out int iboHandle)) return;
|
||||
if (!_iboCache.TryGetValue(iboKey, out int iboHandle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PrimitiveType mode = OGLEnumConverter.GetPrimitiveType(primType);
|
||||
|
||||
|
|
|
@ -110,14 +110,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
//Texture was deleted, the handle is no longer valid, so
|
||||
//reset all uses of this handle on a render target.
|
||||
for (int attachment = 0; attachment < RenderTargetsCount; attachment++)
|
||||
if (_colorHandles[attachment] == handle) _colorHandles[attachment] = 0;
|
||||
{
|
||||
if (_colorHandles[attachment] == handle)
|
||||
{
|
||||
_colorHandles[attachment] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_zetaHandle == handle) _zetaHandle = 0;
|
||||
if (_zetaHandle == handle)
|
||||
{
|
||||
_zetaHandle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind()
|
||||
{
|
||||
if (_dummyFrameBuffer == 0) _dummyFrameBuffer = GL.GenFramebuffer();
|
||||
if (_dummyFrameBuffer == 0)
|
||||
{
|
||||
_dummyFrameBuffer = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _dummyFrameBuffer);
|
||||
|
||||
|
@ -129,9 +140,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
int handle = 0;
|
||||
|
||||
if (key != 0 && _texture.TryGetImageHandler(key, out cachedImage)) handle = cachedImage.Handle;
|
||||
if (key != 0 && _texture.TryGetImageHandler(key, out cachedImage))
|
||||
{
|
||||
handle = cachedImage.Handle;
|
||||
}
|
||||
|
||||
if (handle == _colorHandles[attachment]) continue;
|
||||
if (handle == _colorHandles[attachment])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
|
@ -188,20 +205,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
|
||||
if (OGLExtension.ViewportArray)
|
||||
{
|
||||
GL.ViewportArray(0, RenderTargetsCount, _viewports);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.Viewport(
|
||||
(int)_viewports[0],
|
||||
(int)_viewports[1],
|
||||
(int)_viewports[2],
|
||||
(int)_viewports[3]);
|
||||
}
|
||||
|
||||
if (_attachments.MapCount > 1)
|
||||
{
|
||||
GL.DrawBuffers(_attachments.MapCount, _attachments.Map);
|
||||
}
|
||||
else if (_attachments.MapCount == 1)
|
||||
{
|
||||
GL.DrawBuffer((DrawBufferMode)_attachments.Map[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.DrawBuffer(DrawBufferMode.None);
|
||||
}
|
||||
|
||||
_oldAttachments.Update(_attachments);
|
||||
}
|
||||
|
@ -237,7 +264,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
_attachments.MapCount = map.Length;
|
||||
|
||||
for (int attachment = 0; attachment < _attachments.MapCount; attachment++) _attachments.Map[attachment] = DrawBuffersEnum.ColorAttachment0 + map[attachment];
|
||||
for (int attachment = 0; attachment < _attachments.MapCount; attachment++)
|
||||
{
|
||||
_attachments.Map[attachment] = DrawBuffersEnum.ColorAttachment0 + map[attachment];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -273,7 +303,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void Render()
|
||||
{
|
||||
if (_readTex == null) return;
|
||||
if (_readTex == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int srcX0, srcX1, srcY0, srcY1;
|
||||
|
||||
|
@ -316,7 +349,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
GL.Viewport(0, 0, _window.Width, _window.Height);
|
||||
|
||||
if (_srcFb == 0) _srcFb = GL.GenFramebuffer();
|
||||
if (_srcFb == 0)
|
||||
{
|
||||
_srcFb = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _srcFb);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
|
||||
|
@ -352,11 +388,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
if (srcTex.HasColor != dstTex.HasColor ||
|
||||
srcTex.HasDepth != dstTex.HasDepth ||
|
||||
srcTex.HasStencil != dstTex.HasStencil)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (_srcFb == 0) _srcFb = GL.GenFramebuffer();
|
||||
if (_srcFb == 0)
|
||||
{
|
||||
_srcFb = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
if (_dstFb == 0) _dstFb = GL.GenFramebuffer();
|
||||
if (_dstFb == 0)
|
||||
{
|
||||
_dstFb = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _srcFb);
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _dstFb);
|
||||
|
@ -385,17 +429,29 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void Reinterpret(long key, GalImage newImage)
|
||||
{
|
||||
if (!_texture.TryGetImage(key, out GalImage oldImage)) return;
|
||||
if (!_texture.TryGetImage(key, out GalImage oldImage))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (newImage.Format == oldImage.Format) return;
|
||||
if (newImage.Format == oldImage.Format)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_copyPbo == 0) _copyPbo = GL.GenBuffer();
|
||||
if (_copyPbo == 0)
|
||||
{
|
||||
_copyPbo = GL.GenBuffer();
|
||||
}
|
||||
|
||||
GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyPbo);
|
||||
|
||||
GL.BufferData(BufferTarget.PixelPackBuffer, Math.Max(ImageUtils.GetSize(oldImage), ImageUtils.GetSize(newImage)), IntPtr.Zero, BufferUsageHint.StreamCopy);
|
||||
|
||||
if (!_texture.TryGetImageHandler(key, out ImageHandler cachedImage)) throw new InvalidOperationException();
|
||||
if (!_texture.TryGetImageHandler(key, out ImageHandler cachedImage))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
(_, PixelFormat format, PixelType type) = OGLEnumConverter.GetImageFormat(cachedImage.Format);
|
||||
|
||||
|
@ -414,15 +470,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
private static FramebufferAttachment GetAttachment(ImageHandler cachedImage)
|
||||
{
|
||||
if (cachedImage.HasColor)
|
||||
{
|
||||
return FramebufferAttachment.ColorAttachment0;
|
||||
}
|
||||
else if (cachedImage.HasDepth && cachedImage.HasStencil)
|
||||
{
|
||||
return FramebufferAttachment.DepthStencilAttachment;
|
||||
}
|
||||
else if (cachedImage.HasDepth)
|
||||
{
|
||||
return FramebufferAttachment.DepthAttachment;
|
||||
}
|
||||
else if (cachedImage.HasStencil)
|
||||
{
|
||||
return FramebufferAttachment.StencilAttachment;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static ClearBufferMask GetClearMask(ImageHandler cachedImage)
|
||||
|
|
|
@ -45,7 +45,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
int count = _actionsQueue.Count;
|
||||
|
||||
while (count-- > 0 && _actionsQueue.TryDequeue(out Action renderAction)) renderAction();
|
||||
while (count-- > 0 && _actionsQueue.TryDequeue(out Action renderAction))
|
||||
{
|
||||
renderAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -73,21 +73,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
string code = program.Code;
|
||||
|
||||
if (ShaderDumper.IsDumpEnabled()) code = "//Shader " + shaderDumpIndex + Environment.NewLine + code;
|
||||
if (ShaderDumper.IsDumpEnabled())
|
||||
{
|
||||
code = "//Shader " + shaderDumpIndex + Environment.NewLine + code;
|
||||
}
|
||||
|
||||
return new OGLShaderStage(type, code, program.Uniforms, program.Textures);
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long key)
|
||||
{
|
||||
if (_stages.TryGetValue(key, out OGLShaderStage stage)) return stage.ConstBufferUsage;
|
||||
if (_stages.TryGetValue(key, out OGLShaderStage stage))
|
||||
{
|
||||
return stage.ConstBufferUsage;
|
||||
}
|
||||
|
||||
return Enumerable.Empty<ShaderDeclInfo>();
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long key)
|
||||
{
|
||||
if (_stages.TryGetValue(key, out OGLShaderStage stage)) return stage.TextureUsage;
|
||||
if (_stages.TryGetValue(key, out OGLShaderStage stage))
|
||||
{
|
||||
return stage.TextureUsage;
|
||||
}
|
||||
|
||||
return Enumerable.Empty<ShaderDeclInfo>();
|
||||
}
|
||||
|
@ -113,13 +122,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void Bind(long key)
|
||||
{
|
||||
if (_stages.TryGetValue(key, out OGLShaderStage stage)) Bind(stage);
|
||||
if (_stages.TryGetValue(key, out OGLShaderStage stage))
|
||||
{
|
||||
Bind(stage);
|
||||
}
|
||||
}
|
||||
|
||||
private void Bind(OGLShaderStage stage)
|
||||
{
|
||||
if (stage.Type == GalShaderType.Geometry)
|
||||
if (!OGLExtension.EnhancedLayouts) return;
|
||||
{
|
||||
if (!OGLExtension.EnhancedLayouts)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (stage.Type)
|
||||
{
|
||||
|
@ -147,7 +164,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
if (Current.Vertex == null ||
|
||||
Current.Fragment == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_programs.TryGetValue(Current, out int handle))
|
||||
{
|
||||
|
@ -209,16 +228,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
void BindUniformBlocksIfNotNull(OGLShaderStage stage)
|
||||
{
|
||||
if (stage != null)
|
||||
{
|
||||
foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage)
|
||||
{
|
||||
int blockIndex = GL.GetUniformBlockIndex(programHandle, declInfo.Name);
|
||||
|
||||
if (blockIndex < 0) throw new InvalidOperationException();
|
||||
if (blockIndex < 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
GL.UniformBlockBinding(programHandle, blockIndex, freeBinding);
|
||||
|
||||
freeBinding++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BindUniformBlocksIfNotNull(Current.Vertex);
|
||||
|
@ -235,6 +259,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
void BindTexturesIfNotNull(OGLShaderStage stage)
|
||||
{
|
||||
if (stage != null)
|
||||
{
|
||||
foreach (ShaderDeclInfo decl in stage.TextureUsage)
|
||||
{
|
||||
int location = GL.GetUniformLocation(programHandle, decl.Name);
|
||||
|
@ -243,6 +268,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GL.UseProgram(programHandle);
|
||||
|
@ -260,7 +286,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
GL.GetProgram(handle, GetProgramParameterName.LinkStatus, out status);
|
||||
|
||||
if (status == 0) throw new ShaderException(GL.GetProgramInfoLog(handle));
|
||||
if (status == 0)
|
||||
{
|
||||
throw new ShaderException(GL.GetProgramInfoLog(handle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -77,7 +77,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
GL.GetShader(handle, ShaderParameter.CompileStatus, out status);
|
||||
|
||||
if (status == 0) throw new ShaderException(GL.GetShaderInfoLog(handle));
|
||||
if (status == 0)
|
||||
{
|
||||
throw new ShaderException(GL.GetShaderInfoLog(handle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
_textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)size);
|
||||
|
||||
if (ImageUtils.IsCompressed(image.Format)) throw new InvalidOperationException("Surfaces with compressed formats are not supported!");
|
||||
if (ImageUtils.IsCompressed(image.Format))
|
||||
{
|
||||
throw new InvalidOperationException("Surfaces with compressed formats are not supported!");
|
||||
}
|
||||
|
||||
(PixelInternalFormat internalFmt,
|
||||
PixelFormat format,
|
||||
|
@ -144,7 +147,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public bool TryGetImageHandler(long key, out ImageHandler cachedImage)
|
||||
{
|
||||
if (_textureCache.TryGetValue(key, out cachedImage)) return true;
|
||||
if (_textureCache.TryGetValue(key, out cachedImage))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
cachedImage = null;
|
||||
|
||||
|
|
|
@ -108,13 +108,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
int index = 0;
|
||||
|
||||
for (int attachment = 0; attachment < 8; attachment++)
|
||||
for (int component = 0; component < 4; component++)
|
||||
if (header.OmapTargets[attachment].ComponentEnabled(component))
|
||||
{
|
||||
for (int component = 0; component < 4; component++)
|
||||
{
|
||||
if (header.OmapTargets[attachment].ComponentEnabled(component))
|
||||
{
|
||||
_gprs.TryAdd(index, new ShaderDeclInfo(GetGprName(index), index));
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (header.OmapDepth)
|
||||
{
|
||||
|
@ -128,7 +132,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
ShaderIrNode[] nodes = block.GetNodes();
|
||||
|
||||
foreach (ShaderIrNode node in nodes) Traverse(nodes, null, node);
|
||||
foreach (ShaderIrNode node in nodes)
|
||||
{
|
||||
Traverse(nodes, null, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,15 +153,23 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Merge(combined._preds, vpA._preds, vpB._preds);
|
||||
|
||||
//Merge input attributes.
|
||||
foreach (KeyValuePair<int, ShaderDeclInfo> kv in vpA._inAttributes) combined._inAttributes.TryAdd(kv.Key, kv.Value);
|
||||
foreach (KeyValuePair<int, ShaderDeclInfo> kv in vpA._inAttributes)
|
||||
{
|
||||
combined._inAttributes.TryAdd(kv.Key, kv.Value);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<int, ShaderDeclInfo> kv in vpB._inAttributes)
|
||||
//If Vertex Program A already writes to this attribute,
|
||||
{
|
||||
//If Vertex Program A already writes to this attribute,
|
||||
//then we don't need to add it as an input attribute since
|
||||
//Vertex Program A will already have written to it anyway,
|
||||
//and there's no guarantee that there is an input attribute
|
||||
//for this slot.
|
||||
if (!vpA._outAttributes.ContainsKey(kv.Key)) combined._inAttributes.TryAdd(kv.Key, kv.Value);
|
||||
if (!vpA._outAttributes.ContainsKey(kv.Key))
|
||||
{
|
||||
combined._inAttributes.TryAdd(kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
@ -169,9 +184,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Dictionary<int, ShaderDeclInfo> a,
|
||||
Dictionary<int, ShaderDeclInfo> b)
|
||||
{
|
||||
foreach (KeyValuePair<int, ShaderDeclInfo> kv in a) c.TryAdd(kv.Key, kv.Value);
|
||||
foreach (KeyValuePair<int, ShaderDeclInfo> kv in a)
|
||||
{
|
||||
c.TryAdd(kv.Key, kv.Value);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<int, ShaderDeclInfo> kv in b) c.TryAdd(kv.Key, kv.Value);
|
||||
foreach (KeyValuePair<int, ShaderDeclInfo> kv in b)
|
||||
{
|
||||
c.TryAdd(kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void Traverse(ShaderIrNode[] nodes, ShaderIrNode parent, ShaderIrNode node)
|
||||
|
@ -223,13 +244,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
ShaderIrNode curr = nodes[index];
|
||||
|
||||
if (curr is ShaderIrAsg asg && asg.Dst is ShaderIrOperGpr gpr)
|
||||
if (gpr.Index == ((ShaderIrOperGpr)op.OperandC).Index)
|
||||
{
|
||||
if (gpr.Index == ((ShaderIrOperGpr)op.OperandC).Index)
|
||||
{
|
||||
handleSrc = asg.Src;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (handleSrc != null && handleSrc is ShaderIrOperCbuf cbuf)
|
||||
{
|
||||
|
@ -268,16 +291,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
abuf.Offs == VertexIdAttr ||
|
||||
abuf.Offs == InstanceIdAttr ||
|
||||
abuf.Offs == FaceAttr)
|
||||
break;
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
int index = abuf.Offs >> 4;
|
||||
int index = abuf.Offs >> 4;
|
||||
int elem = (abuf.Offs >> 2) & 3;
|
||||
|
||||
int glslIndex = index - AttrStartIndex;
|
||||
|
||||
if (glslIndex < 0) return;
|
||||
if (glslIndex < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ShaderDeclInfo declInfo;
|
||||
ShaderDeclInfo declInfo;
|
||||
|
||||
if (parent is ShaderIrAsg asg && asg.Dst == node)
|
||||
{
|
||||
|
@ -344,7 +372,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
int vecIndex = index & ~3;
|
||||
|
||||
if (decls.TryGetValue(vecIndex, out ShaderDeclInfo declInfo))
|
||||
if (declInfo.Size > 1 && index < vecIndex + declInfo.Size) return true;
|
||||
{
|
||||
if (declInfo.Size > 1 && index < vecIndex + declInfo.Size)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return decls.ContainsKey(index);
|
||||
}
|
||||
|
|
|
@ -217,7 +217,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private void PrintDeclTextures()
|
||||
{
|
||||
foreach (ShaderDeclInfo declInfo in IterateCbTextures()) _sb.AppendLine("uniform sampler2D " + declInfo.Name + ";");
|
||||
foreach (ShaderDeclInfo declInfo in IterateCbTextures())
|
||||
{
|
||||
_sb.AppendLine("uniform sampler2D " + declInfo.Name + ";");
|
||||
}
|
||||
|
||||
PrintDecls(_decl.Textures, "uniform sampler2D");
|
||||
}
|
||||
|
@ -227,7 +230,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
HashSet<string> names = new HashSet<string>();
|
||||
|
||||
foreach (ShaderDeclInfo declInfo in _decl.CbTextures.Values.OrderBy(DeclKeySelector))
|
||||
if (names.Add(declInfo.Name)) yield return declInfo;
|
||||
{
|
||||
if (names.Add(declInfo.Name))
|
||||
{
|
||||
yield return declInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintDeclUniforms()
|
||||
|
@ -256,7 +264,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
_sb.AppendLine("};");
|
||||
}
|
||||
|
||||
if (_decl.Uniforms.Count > 0) _sb.AppendLine();
|
||||
if (_decl.Uniforms.Count > 0)
|
||||
{
|
||||
_sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintDeclAttributes()
|
||||
|
@ -268,7 +279,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private void PrintDeclInAttributes()
|
||||
{
|
||||
if (_decl.ShaderType == GalShaderType.Fragment) _sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") in vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||
if (_decl.ShaderType == GalShaderType.Fragment)
|
||||
{
|
||||
_sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") in vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||
}
|
||||
|
||||
if (_decl.ShaderType == GalShaderType.Geometry)
|
||||
{
|
||||
|
@ -277,7 +291,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
_sb.AppendLine("in Vertex {");
|
||||
|
||||
foreach (ShaderDeclInfo declInfo in _decl.InAttributes.Values.OrderBy(DeclKeySelector))
|
||||
if (declInfo.Index >= 0) _sb.AppendLine(IdentationStr + "layout (location = " + declInfo.Index + ") vec4 " + declInfo.Name + "; ");
|
||||
{
|
||||
if (declInfo.Index >= 0)
|
||||
{
|
||||
_sb.AppendLine(IdentationStr + "layout (location = " + declInfo.Index + ") vec4 " + declInfo.Name + "; ");
|
||||
}
|
||||
}
|
||||
|
||||
_sb.AppendLine("} block_in[];" + Environment.NewLine);
|
||||
}
|
||||
|
@ -295,14 +314,19 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
int count = 0;
|
||||
|
||||
for (int attachment = 0; attachment < 8; attachment++)
|
||||
{
|
||||
if (_header.OmapTargets[attachment].Enabled)
|
||||
{
|
||||
_sb.AppendLine("layout (location = " + attachment + ") out vec4 " + GlslDecl.FragmentOutputName + attachment + ";");
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0) _sb.AppendLine();
|
||||
if (count > 0)
|
||||
{
|
||||
_sb.AppendLine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -318,14 +342,19 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
int count = 0;
|
||||
|
||||
foreach (ShaderDeclInfo declInfo in decls.OrderBy(DeclKeySelector))
|
||||
{
|
||||
if (declInfo.Index >= 0)
|
||||
{
|
||||
_sb.AppendLine("layout (location = " + declInfo.Index + ") " + inOut + " vec4 " + declInfo.Name + ";");
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0) _sb.AppendLine();
|
||||
if (count > 0)
|
||||
{
|
||||
_sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintDeclGprs()
|
||||
|
@ -352,16 +381,25 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
string name;
|
||||
|
||||
if (customType != null)
|
||||
{
|
||||
name = customType + " " + declInfo.Name + suffix + ";";
|
||||
}
|
||||
else if (declInfo.Name.Contains(GlslDecl.FragmentOutputName))
|
||||
{
|
||||
name = "layout (location = " + declInfo.Index / 4 + ") out vec4 " + declInfo.Name + suffix + ";";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = GetDecl(declInfo) + suffix + ";";
|
||||
}
|
||||
|
||||
_sb.AppendLine(name);
|
||||
}
|
||||
|
||||
if (dict.Count > 0) _sb.AppendLine();
|
||||
if (dict.Count > 0)
|
||||
{
|
||||
_sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
private int DeclKeySelector(ShaderDeclInfo declInfo)
|
||||
|
@ -372,9 +410,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
private string GetDecl(ShaderDeclInfo declInfo)
|
||||
{
|
||||
if (declInfo.Size == 4)
|
||||
{
|
||||
return "vec4 " + declInfo.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "float " + declInfo.Name;
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintMain()
|
||||
|
@ -383,11 +425,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
foreach (KeyValuePair<int, ShaderDeclInfo> kv in _decl.InAttributes)
|
||||
{
|
||||
if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr)) continue;
|
||||
if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ShaderDeclInfo declInfo = kv.Value;
|
||||
|
||||
if (_decl.ShaderType == GalShaderType.Geometry)
|
||||
{
|
||||
for (int vertex = 0; vertex < MaxVertexInput; vertex++)
|
||||
{
|
||||
string dst = attr.Name + "[" + vertex + "]";
|
||||
|
@ -396,8 +442,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
_sb.AppendLine(IdentationStr + dst + " = " + src + ";");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_sb.AppendLine(IdentationStr + attr.Name + " = " + declInfo.Name + ";");
|
||||
}
|
||||
}
|
||||
|
||||
_sb.AppendLine(IdentationStr + "uint pc;");
|
||||
|
@ -412,11 +461,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
PrintProgram(_blocks, GlslDecl.BasicBlockName);
|
||||
}
|
||||
|
||||
if (_decl.ShaderType != GalShaderType.Geometry) PrintAttrToOutput();
|
||||
if (_decl.ShaderType != GalShaderType.Geometry)
|
||||
{
|
||||
PrintAttrToOutput();
|
||||
}
|
||||
|
||||
if (_decl.ShaderType == GalShaderType.Fragment)
|
||||
{
|
||||
if (_header.OmapDepth) _sb.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(_header.DepthRegister) + ";");
|
||||
if (_header.OmapDepth)
|
||||
{
|
||||
_sb.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(_header.DepthRegister) + ";");
|
||||
}
|
||||
|
||||
int gprIndex = 0;
|
||||
|
||||
|
@ -427,12 +482,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
OmapTarget target = _header.OmapTargets[attachment];
|
||||
|
||||
for (int component = 0; component < 4; component++)
|
||||
{
|
||||
if (target.ComponentEnabled(component))
|
||||
{
|
||||
_sb.AppendLine(IdentationStr + output + "[" + component + "] = " + GlslDecl.GetGprName(gprIndex) + ";");
|
||||
|
||||
gprIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -469,18 +526,27 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
foreach (KeyValuePair<int, ShaderDeclInfo> kv in _decl.OutAttributes)
|
||||
{
|
||||
if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr)) continue;
|
||||
if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ShaderDeclInfo declInfo = kv.Value;
|
||||
|
||||
string name = attr.Name;
|
||||
|
||||
if (_decl.ShaderType == GalShaderType.Geometry) name += "[0]";
|
||||
if (_decl.ShaderType == GalShaderType.Geometry)
|
||||
{
|
||||
name += "[0]";
|
||||
}
|
||||
|
||||
_sb.AppendLine(identation + declInfo.Name + " = " + name + ";");
|
||||
}
|
||||
|
||||
if (_decl.ShaderType == GalShaderType.Vertex) _sb.AppendLine(identation + "gl_Position.xy *= " + GlslDecl.FlipUniformName + ";");
|
||||
if (_decl.ShaderType == GalShaderType.Vertex)
|
||||
{
|
||||
_sb.AppendLine(identation + "gl_Position.xy *= " + GlslDecl.FlipUniformName + ";");
|
||||
}
|
||||
|
||||
if (_decl.ShaderType != GalShaderType.Fragment)
|
||||
{
|
||||
|
@ -503,7 +569,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private void PrintNodes(ShaderIrBlock block, ShaderIrNode[] nodes)
|
||||
{
|
||||
foreach (ShaderIrNode node in nodes) PrintNode(block, node, IdentationStr);
|
||||
foreach (ShaderIrNode node in nodes)
|
||||
{
|
||||
PrintNode(block, node, IdentationStr);
|
||||
}
|
||||
|
||||
if (nodes.Length == 0)
|
||||
{
|
||||
|
@ -517,6 +586,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
bool unconditionalFlowChange = false;
|
||||
|
||||
if (last is ShaderIrOp op)
|
||||
{
|
||||
switch (op.Inst)
|
||||
{
|
||||
case ShaderIrInst.Bra:
|
||||
|
@ -525,13 +595,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
unconditionalFlowChange = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!unconditionalFlowChange)
|
||||
{
|
||||
if (block.Next != null)
|
||||
{
|
||||
_sb.AppendLine(IdentationStr + "return " + GetBlockPosition(block.Next) + ";");
|
||||
}
|
||||
else
|
||||
{
|
||||
_sb.AppendLine(IdentationStr + "return 0u;");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -541,7 +616,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
string ifExpr = GetSrcExpr(cond.Pred, true);
|
||||
|
||||
if (cond.Not) ifExpr = "!(" + ifExpr + ")";
|
||||
if (cond.Not)
|
||||
{
|
||||
ifExpr = "!(" + ifExpr + ")";
|
||||
}
|
||||
|
||||
_sb.AppendLine(identation + "if (" + ifExpr + ") {");
|
||||
|
||||
|
@ -625,8 +703,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
private bool IsValidOutOper(ShaderIrNode node)
|
||||
{
|
||||
if (node is ShaderIrOperGpr gpr && gpr.IsConst)
|
||||
{
|
||||
return false;
|
||||
else if (node is ShaderIrOperPred pred && pred.IsConst) return false;
|
||||
}
|
||||
else if (node is ShaderIrOperPred pred && pred.IsConst)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -634,10 +717,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
private string GetDstOperName(ShaderIrNode node)
|
||||
{
|
||||
if (node is ShaderIrOperAbuf abuf)
|
||||
{
|
||||
return GetOutAbufName(abuf);
|
||||
}
|
||||
else if (node is ShaderIrOperGpr gpr)
|
||||
{
|
||||
return GetName(gpr);
|
||||
else if (node is ShaderIrOperPred pred) return GetName(pred);
|
||||
}
|
||||
else if (node is ShaderIrOperPred pred)
|
||||
{
|
||||
return GetName(pred);
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(node));
|
||||
}
|
||||
|
@ -657,11 +747,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
string expr;
|
||||
|
||||
if (_instsExpr.TryGetValue(op.Inst, out GetInstExpr getExpr))
|
||||
{
|
||||
expr = getExpr(op);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(op.Inst.ToString());
|
||||
}
|
||||
|
||||
if (!entry && NeedsParentheses(op)) expr = "(" + expr + ")";
|
||||
if (!entry && NeedsParentheses(op))
|
||||
{
|
||||
expr = "(" + expr + ")";
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
||||
|
@ -685,7 +782,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private string GetName(ShaderIrOperCbuf cbuf)
|
||||
{
|
||||
if (!_decl.Uniforms.TryGetValue(cbuf.Index, out ShaderDeclInfo declInfo)) throw new InvalidOperationException();
|
||||
if (!_decl.Uniforms.TryGetValue(cbuf.Index, out ShaderDeclInfo declInfo))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (cbuf.Offs != null)
|
||||
{
|
||||
|
@ -704,10 +804,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
private string GetOutAbufName(ShaderIrOperAbuf abuf)
|
||||
{
|
||||
if (_decl.ShaderType == GalShaderType.Geometry)
|
||||
{
|
||||
switch (abuf.Offs)
|
||||
{
|
||||
case GlslDecl.LayerAttr: return "gl_Layer";
|
||||
}
|
||||
}
|
||||
|
||||
return GetAttrTempName(abuf);
|
||||
}
|
||||
|
@ -716,19 +818,24 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
//Handle special scalar read-only attributes here.
|
||||
if (_decl.ShaderType == GalShaderType.Vertex)
|
||||
{
|
||||
switch (abuf.Offs)
|
||||
{
|
||||
case GlslDecl.VertexIdAttr: return "gl_VertexID";
|
||||
case GlslDecl.InstanceIdAttr: return GlslDecl.InstanceUniformName;
|
||||
}
|
||||
}
|
||||
else if (_decl.ShaderType == GalShaderType.TessEvaluation)
|
||||
{
|
||||
switch (abuf.Offs)
|
||||
{
|
||||
case GlslDecl.TessCoordAttrX: return "gl_TessCoord.x";
|
||||
case GlslDecl.TessCoordAttrY: return "gl_TessCoord.y";
|
||||
case GlslDecl.TessCoordAttrZ: return "gl_TessCoord.z";
|
||||
}
|
||||
}
|
||||
else if (_decl.ShaderType == GalShaderType.Fragment)
|
||||
{
|
||||
switch (abuf.Offs)
|
||||
{
|
||||
case GlslDecl.PointCoordAttrX: return "gl_PointCoord.x";
|
||||
|
@ -737,6 +844,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
//Note: It's a guess that Maxwell's face is 1 when gl_FrontFacing == true
|
||||
case GlslDecl.FaceAttr: return "(gl_FrontFacing ? 1 : 0)";
|
||||
}
|
||||
}
|
||||
|
||||
return GetAttrTempName(abuf);
|
||||
}
|
||||
|
@ -766,7 +874,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
if (declInfo.Index >= 16) throw new InvalidOperationException($"Shader attribute offset {abuf.Offs} is invalid.");
|
||||
if (declInfo.Index >= 16)
|
||||
{
|
||||
throw new InvalidOperationException($"Shader attribute offset {abuf.Offs} is invalid.");
|
||||
}
|
||||
|
||||
if (_decl.ShaderType == GalShaderType.Geometry)
|
||||
{
|
||||
|
@ -790,9 +901,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
//Only use hex is the value is too big and would likely be hard to read as int.
|
||||
if (imm.Value > 0xfff ||
|
||||
imm.Value < -0xfff)
|
||||
{
|
||||
return "0x" + imm.Value.ToString("x8", CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetIntConst(imm.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetValue(ShaderIrOperImmf immf)
|
||||
|
@ -810,9 +925,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
int vecIndex = index & ~3;
|
||||
|
||||
if (dict.TryGetValue(vecIndex, out ShaderDeclInfo declInfo))
|
||||
if (declInfo.Size > 1 && index < vecIndex + declInfo.Size) return declInfo.Name + "." + GetAttrSwizzle(index & 3);
|
||||
{
|
||||
if (declInfo.Size > 1 && index < vecIndex + declInfo.Size)
|
||||
{
|
||||
return declInfo.Name + "." + GetAttrSwizzle(index & 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dict.TryGetValue(index, out declInfo)) throw new InvalidOperationException();
|
||||
if (!dict.TryGetValue(index, out declInfo))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return declInfo.Name;
|
||||
}
|
||||
|
@ -1033,6 +1156,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
int elem = (abuf.Offs >> 2) & 3;
|
||||
|
||||
if (_decl.ShaderType == GalShaderType.Fragment && index == GlslDecl.GlPositionVec4Index)
|
||||
{
|
||||
switch (elem)
|
||||
{
|
||||
case 0: return "gl_FragCoord.x";
|
||||
|
@ -1040,6 +1164,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
case 2: return "gl_FragCoord.z";
|
||||
case 3: return "1";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GetSrcExpr(op.OperandA);
|
||||
|
@ -1105,7 +1230,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
|
||||
|
||||
if (!_decl.CbTextures.TryGetValue(op, out ShaderDeclInfo declInfo)) throw new InvalidOperationException();
|
||||
if (!_decl.CbTextures.TryGetValue(op, out ShaderDeclInfo declInfo))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
string coords = GetTexSamplerCoords(op);
|
||||
|
||||
|
@ -1229,7 +1357,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
int handle = ((ShaderIrOperImm)op.OperandC).Value;
|
||||
|
||||
if (!_decl.Textures.TryGetValue(handle, out ShaderDeclInfo declInfo)) throw new InvalidOperationException();
|
||||
if (!_decl.Textures.TryGetValue(handle, out ShaderDeclInfo declInfo))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return declInfo.Name;
|
||||
}
|
||||
|
@ -1266,7 +1397,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
//(like bool to int/float and others).
|
||||
if (srcType != OperType.F32 &&
|
||||
srcType != OperType.I32)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
switch (src)
|
||||
{
|
||||
|
@ -1274,8 +1407,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
//When the Gpr is ZR, just return the 0 value directly,
|
||||
//since the float encoding for 0 is 0.
|
||||
if (gpr.IsConst) return "0";
|
||||
break;
|
||||
if (gpr.IsConst)
|
||||
{
|
||||
return "0";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ShaderIrOperImm imm:
|
||||
|
@ -1286,8 +1423,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
float value = BitConverter.Int32BitsToSingle(imm.Value);
|
||||
|
||||
if (!float.IsNaN(value) && !float.IsInfinity(value)) return GetFloatConst(value);
|
||||
}
|
||||
if (!float.IsNaN(value) && !float.IsInfinity(value))
|
||||
{
|
||||
return GetFloatConst(value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1321,6 +1461,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
//Special case instructions with the result type different
|
||||
//from the input types (like integer <-> float conversion) here.
|
||||
if (node is ShaderIrOp op)
|
||||
{
|
||||
switch (op.Inst)
|
||||
{
|
||||
case ShaderIrInst.Stof:
|
||||
|
@ -1332,6 +1473,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
case ShaderIrInst.Ftou:
|
||||
return OperType.I32;
|
||||
}
|
||||
}
|
||||
|
||||
return GetSrcNodeType(node);
|
||||
}
|
||||
|
@ -1357,13 +1499,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
case ShaderIrOp op:
|
||||
if (op.Inst > ShaderIrInst.BStart &&
|
||||
op.Inst < ShaderIrInst.BEnd)
|
||||
{
|
||||
return OperType.Bool;
|
||||
}
|
||||
else if (op.Inst > ShaderIrInst.FStart &&
|
||||
op.Inst < ShaderIrInst.FEnd)
|
||||
{
|
||||
return OperType.F32;
|
||||
}
|
||||
else if (op.Inst > ShaderIrInst.Start &&
|
||||
op.Inst < ShaderIrInst.End)
|
||||
{
|
||||
return OperType.I32;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1373,9 +1522,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
private static string GetBlockPosition(ShaderIrBlock block)
|
||||
{
|
||||
if (block != null)
|
||||
{
|
||||
return "0x" + block.Position.ToString("x8") + "u";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "0u";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -351,9 +351,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
ShaderIrNode operA = opCode.Pred12();
|
||||
ShaderIrNode operB = opCode.Pred29();
|
||||
|
||||
if (negA) operA = new ShaderIrOp(ShaderIrInst.Bnot, operA);
|
||||
if (negA)
|
||||
{
|
||||
operA = new ShaderIrOp(ShaderIrInst.Bnot, operA);
|
||||
}
|
||||
|
||||
if (negB) operB = new ShaderIrOp(ShaderIrInst.Bnot, operB);
|
||||
if (negB)
|
||||
{
|
||||
operB = new ShaderIrOp(ShaderIrInst.Bnot, operB);
|
||||
}
|
||||
|
||||
ShaderIrOp op = new ShaderIrOp(lopInst, operA, operB);
|
||||
|
||||
|
@ -365,11 +371,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
lopInst = opCode.BLop45();
|
||||
|
||||
if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst) return;
|
||||
if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ShaderIrNode p2NNode = p2Node;
|
||||
|
||||
if (negP) p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode);
|
||||
if (negP)
|
||||
{
|
||||
p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode);
|
||||
}
|
||||
|
||||
op = new ShaderIrOp(ShaderIrInst.Bnot, p0Node);
|
||||
|
||||
|
@ -441,9 +453,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
ShaderIrNode operB;
|
||||
|
||||
if (opCode.Read(50))
|
||||
{
|
||||
operB = opCode.Gpr20();
|
||||
}
|
||||
else
|
||||
{
|
||||
operB = opCode.Imm19_20();
|
||||
}
|
||||
|
||||
ShaderIrOperGpr operC = opCode.Gpr39();
|
||||
|
||||
|
@ -635,9 +651,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
operB = GetAluFneg(operB, negB);
|
||||
|
||||
if (oper == ShaderOper.Rc)
|
||||
{
|
||||
operC = GetAluFneg(opCode.Cbuf34(), negC);
|
||||
}
|
||||
else
|
||||
{
|
||||
operC = GetAluFneg(opCode.Gpr39(), negC);
|
||||
}
|
||||
|
||||
ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Ffma, operA, operB, operC);
|
||||
|
||||
|
@ -694,7 +714,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
ShaderIrNode ApplyHeight(ShaderIrNode src, int height)
|
||||
{
|
||||
if (oper != ShaderOper.Rr) return src;
|
||||
if (oper != ShaderOper.Rr)
|
||||
{
|
||||
return src;
|
||||
}
|
||||
|
||||
switch (height)
|
||||
{
|
||||
|
@ -713,11 +736,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
ShaderIrOp sum = new ShaderIrOp(ShaderIrInst.Add, src1, src2);
|
||||
|
||||
if (oper == ShaderOper.Rr)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 1: sum = new ShaderIrOp(ShaderIrInst.Lsr, sum, new ShaderIrOperImm(16)); break;
|
||||
case 2: sum = new ShaderIrOp(ShaderIrInst.Lsl, sum, new ShaderIrOperImm(16)); break;
|
||||
}
|
||||
}
|
||||
|
||||
//Note: Here there should be a "+ 1" when carry flag is set
|
||||
//but since carry is mostly ignored by other instructions, it's excluded for now
|
||||
|
@ -772,9 +797,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
ShaderIrNode operA = opCode.Gpr8(), operB;
|
||||
|
||||
if (isFloat)
|
||||
{
|
||||
operA = GetAluFabsFneg(operA, absA, negA);
|
||||
}
|
||||
else
|
||||
{
|
||||
operA = GetAluIabsIneg(operA, absA, negA);
|
||||
}
|
||||
|
||||
switch (oper)
|
||||
{
|
||||
|
@ -787,9 +816,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
|
||||
if (isFloat)
|
||||
{
|
||||
operB = GetAluFabsFneg(operB, absB, negB);
|
||||
}
|
||||
else
|
||||
{
|
||||
operB = GetAluIabsIneg(operB, absB, negB);
|
||||
}
|
||||
|
||||
ShaderIrOperPred pred = opCode.Pred39();
|
||||
|
||||
|
@ -985,11 +1018,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
ShaderIrInst lopInst = opCode.BLop45();
|
||||
|
||||
if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst) return;
|
||||
if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ShaderIrNode p2NNode = p2Node;
|
||||
|
||||
if (negP) p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode);
|
||||
if (negP)
|
||||
{
|
||||
p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode);
|
||||
}
|
||||
|
||||
op = new ShaderIrOp(ShaderIrInst.Bnot, p0Node);
|
||||
|
||||
|
@ -1035,9 +1074,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
ShaderIrNode op;
|
||||
|
||||
if (subOp < 3)
|
||||
{
|
||||
op = new ShaderIrOp(inst, operA, operB);
|
||||
}
|
||||
else
|
||||
{
|
||||
op = operB;
|
||||
}
|
||||
|
||||
ShaderIrNode compare = new ShaderIrOp(ShaderIrInst.Cne, op, new ShaderIrOperImm(0));
|
||||
|
||||
|
@ -1065,7 +1108,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
ShaderIrInst shiftAb = signAb ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||
ShaderIrInst shiftC = signC ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||
|
||||
if (highA) operA = new ShaderIrOp(shiftAb, operA, imm16);
|
||||
if (highA)
|
||||
{
|
||||
operA = new ShaderIrOp(shiftAb, operA, imm16);
|
||||
}
|
||||
|
||||
switch (oper)
|
||||
{
|
||||
|
@ -1102,11 +1148,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
ShaderIrNode operBh = operB;
|
||||
|
||||
if (highB) operBh = new ShaderIrOp(shiftAb, operBh, imm16);
|
||||
if (highB)
|
||||
{
|
||||
operBh = new ShaderIrOp(shiftAb, operBh, imm16);
|
||||
}
|
||||
|
||||
ShaderIrOp mulOp = new ShaderIrOp(ShaderIrInst.Mul, operA, operBh);
|
||||
|
||||
if (productShiftLeft) mulOp = new ShaderIrOp(ShaderIrInst.Lsl, mulOp, imm16);
|
||||
if (productShiftLeft)
|
||||
{
|
||||
mulOp = new ShaderIrOp(ShaderIrInst.Lsl, mulOp, imm16);
|
||||
}
|
||||
|
||||
ShaderIrOp addOp = new ShaderIrOp(ShaderIrInst.Add, mulOp, operC);
|
||||
|
||||
|
|
|
@ -6,7 +6,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
public static void Bra(ShaderIrBlock block, long opCode, int position)
|
||||
{
|
||||
if ((opCode & 0x20) != 0) throw new NotImplementedException();
|
||||
if ((opCode & 0x20) != 0)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch());
|
||||
|
||||
|
@ -18,7 +21,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
int cCode = (int)opCode & 0x1f;
|
||||
|
||||
//TODO: Figure out what the other condition codes mean...
|
||||
if (cCode == 0xf) block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit)));
|
||||
if (cCode == 0xf)
|
||||
{
|
||||
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Kil(ShaderIrBlock block, long opCode, int position)
|
||||
|
@ -28,7 +34,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static void Ssy(ShaderIrBlock block, long opCode, int position)
|
||||
{
|
||||
if ((opCode & 0x20) != 0) throw new NotImplementedException();
|
||||
if ((opCode & 0x20) != 0)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch());
|
||||
|
||||
|
|
|
@ -56,7 +56,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
int cbufIndex = opCode.Read(36, 0x1f);
|
||||
int type = opCode.Read(48, 7);
|
||||
|
||||
if (type > 5) throw new InvalidOperationException();
|
||||
if (type > 5)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
ShaderIrOperGpr temp = ShaderIrOperGpr.MakeTemporary();
|
||||
|
||||
|
@ -73,7 +76,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
operA.Pos += index;
|
||||
operD.Index += index;
|
||||
|
||||
if (!operD.IsValidRegister) break;
|
||||
if (!operD.IsValidRegister)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ShaderIrNode node = operA;
|
||||
|
||||
|
@ -147,7 +153,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
coords[index].Index += index;
|
||||
|
||||
if (coords[index].Index > ShaderIrOperGpr.ZrIndex) coords[index].Index = ShaderIrOperGpr.ZrIndex;
|
||||
if (coords[index].Index > ShaderIrOperGpr.ZrIndex)
|
||||
{
|
||||
coords[index].Index = ShaderIrOperGpr.ZrIndex;
|
||||
}
|
||||
}
|
||||
|
||||
int chMask = opCode.Read(31, 0xf);
|
||||
|
@ -173,7 +182,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
for (int ch = 0; ch < 4; ch++)
|
||||
{
|
||||
if (!IsChannelUsed(chMask, ch)) continue;
|
||||
if (!IsChannelUsed(chMask, ch))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ShaderIrOperGpr src = new ShaderIrOperGpr(TempRegStart + ch);
|
||||
|
||||
|
@ -181,7 +193,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
dst.Index += regInc++;
|
||||
|
||||
if (dst.Index >= ShaderIrOperGpr.ZrIndex) continue;
|
||||
if (dst.Index >= ShaderIrOperGpr.ZrIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, src)));
|
||||
}
|
||||
|
@ -209,7 +224,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
lutIndex = opCode.Gpr0 ().Index != ShaderIrOperGpr.ZrIndex ? 1 : 0;
|
||||
lutIndex |= opCode.Gpr28().Index != ShaderIrOperGpr.ZrIndex ? 2 : 0;
|
||||
|
||||
if (lutIndex == 0) return;
|
||||
if (lutIndex == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int chMask = _maskLut[lutIndex, opCode.Read(50, 7)];
|
||||
|
||||
|
@ -248,13 +266,19 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
for (int ch = 0; ch < 4; ch++)
|
||||
{
|
||||
if (!IsChannelUsed(chMask, ch)) continue;
|
||||
if (!IsChannelUsed(chMask, ch))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ShaderIrOperGpr src = new ShaderIrOperGpr(TempRegStart + ch);
|
||||
|
||||
ShaderIrOperGpr dst = GetDst();
|
||||
|
||||
if (dst.Index != ShaderIrOperGpr.ZrIndex) block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, src)));
|
||||
if (dst.Index != ShaderIrOperGpr.ZrIndex)
|
||||
{
|
||||
block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, src)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
ShaderIrInst roundInst = GetRoundInst(opCode);
|
||||
|
||||
if (roundInst != ShaderIrInst.Invalid) operA = new ShaderIrOp(roundInst, operA);
|
||||
if (roundInst != ShaderIrInst.Invalid)
|
||||
{
|
||||
operA = new ShaderIrOp(roundInst, operA);
|
||||
}
|
||||
|
||||
block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA)));
|
||||
}
|
||||
|
@ -179,7 +182,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
if (type == IntType.U64 ||
|
||||
type == IntType.S64)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
bool negA = opCode.Read(45);
|
||||
bool absA = opCode.Read(49);
|
||||
|
@ -199,7 +204,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
ShaderIrInst roundInst = GetRoundInst(opCode);
|
||||
|
||||
if (roundInst != ShaderIrInst.Invalid) operA = new ShaderIrOp(roundInst, operA);
|
||||
if (roundInst != ShaderIrInst.Invalid)
|
||||
{
|
||||
operA = new ShaderIrOp(roundInst, operA);
|
||||
}
|
||||
|
||||
bool signed = type >= IntType.S8;
|
||||
|
||||
|
@ -241,7 +249,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
if (type == IntType.U64 ||
|
||||
type == IntType.S64)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
int sel = opCode.Read(41, 3);
|
||||
|
||||
|
@ -267,9 +277,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
int size = 8 << ((int)type & 3);
|
||||
|
||||
if (shift != 0) operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift));
|
||||
if (shift != 0)
|
||||
{
|
||||
operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift));
|
||||
}
|
||||
|
||||
if (size < 32) operA = ExtendTo32(operA, signed, size);
|
||||
if (size < 32)
|
||||
{
|
||||
operA = ExtendTo32(operA, signed, size);
|
||||
}
|
||||
|
||||
ShaderIrInst inst = signed
|
||||
? ShaderIrInst.Stof
|
||||
|
@ -286,7 +302,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
if (type == IntType.U64 ||
|
||||
type == IntType.S64)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
int sel = opCode.Read(41, 3);
|
||||
|
||||
|
@ -313,7 +331,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
int size = 8 << ((int)type & 3);
|
||||
|
||||
if (shift != 0) operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift));
|
||||
if (shift != 0)
|
||||
{
|
||||
operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift));
|
||||
}
|
||||
|
||||
if (size < 32)
|
||||
{
|
||||
|
@ -376,7 +397,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
IntType type = (IntType)opCode.Read(10, 3);
|
||||
|
||||
if (signed) type += (int)IntType.S8;
|
||||
if (signed)
|
||||
{
|
||||
type += (int)IntType.S8;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
ShaderIrOperAbuf[] opers = new ShaderIrOperAbuf[size + 1];
|
||||
|
||||
for (int index = 0; index <= size; index++) opers[index] = new ShaderIrOperAbuf(abuf + index * 4, vertex);
|
||||
for (int index = 0; index <= size; index++)
|
||||
{
|
||||
opers[index] = new ShaderIrOperAbuf(abuf + index * 4, vertex);
|
||||
}
|
||||
|
||||
return opers;
|
||||
}
|
||||
|
@ -98,7 +101,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
bool neg = opCode.Read(56);
|
||||
|
||||
if (neg) value = -value;
|
||||
if (neg)
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return new ShaderIrOperImm(value);
|
||||
}
|
||||
|
@ -111,7 +117,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
imm <<= 12;
|
||||
|
||||
if (neg) imm |= 0x80000000;
|
||||
if (neg)
|
||||
{
|
||||
imm |= 0x80000000;
|
||||
}
|
||||
|
||||
float value = BitConverter.Int32BitsToSingle((int)imm);
|
||||
|
||||
|
@ -142,7 +151,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
ShaderIrNode node = opCode.Pred39();
|
||||
|
||||
if (opCode.Read(42)) node = new ShaderIrOp(ShaderIrInst.Bnot, node);
|
||||
if (opCode.Read(42))
|
||||
{
|
||||
node = new ShaderIrOp(ShaderIrInst.Bnot, node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -237,7 +249,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
int pred = opCode.Read(16, 0xf);
|
||||
|
||||
if (pred != 0xf) pred &= 7;
|
||||
if (pred != 0xf)
|
||||
{
|
||||
pred &= 7;
|
||||
}
|
||||
|
||||
return new ShaderIrOperPred(pred);
|
||||
}
|
||||
|
|
|
@ -11,9 +11,15 @@
|
|||
|
||||
int type = opCode.Read(39, 3);
|
||||
|
||||
if ((type & 1) != 0) block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Emit)));
|
||||
if ((type & 1) != 0)
|
||||
{
|
||||
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Emit)));
|
||||
}
|
||||
|
||||
if ((type & 2) != 0) block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Cut)));
|
||||
if ((type & 2) != 0)
|
||||
{
|
||||
block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Cut)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
visited.Add(position, output);
|
||||
}
|
||||
|
||||
if (source != null) output.Sources.Add(source);
|
||||
if (source != null)
|
||||
{
|
||||
output.Sources.Add(source);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -70,7 +73,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
if (NodeHasNext(lastNode)) current.Next = Enqueue(current.EndPosition);
|
||||
if (NodeHasNext(lastNode))
|
||||
{
|
||||
current.Next = Enqueue(current.EndPosition);
|
||||
}
|
||||
}
|
||||
|
||||
//If we have on the graph two blocks with the same end position,
|
||||
|
@ -109,8 +115,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
uint firstPos = uint.MaxValue;
|
||||
|
||||
foreach (ShaderIrBlock block in visited.Values)
|
||||
{
|
||||
if (firstPos > (uint)block.Position)
|
||||
{
|
||||
firstPos = (uint)block.Position;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderIrBlock current = visited[(int)firstPos];
|
||||
|
||||
|
@ -169,7 +179,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
block.AddNode(new ShaderIrCmnt(dbgOpCode));
|
||||
}
|
||||
|
||||
if (decode == null) continue;
|
||||
if (decode == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
decode(block, opCode, position);
|
||||
}
|
||||
|
@ -185,14 +198,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private static ShaderIrOp GetInnermostOp(ShaderIrNode node)
|
||||
{
|
||||
if (node is ShaderIrCond cond) node = cond.Child;
|
||||
if (node is ShaderIrCond cond)
|
||||
{
|
||||
node = cond.Child;
|
||||
}
|
||||
|
||||
return node is ShaderIrOp op ? op : null;
|
||||
}
|
||||
|
||||
private static bool NodeHasNext(ShaderIrNode node)
|
||||
{
|
||||
if (!(node is ShaderIrOp op)) return true;
|
||||
if (!(node is ShaderIrOp op))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return op.Inst != ShaderIrInst.Exit &&
|
||||
op.Inst != ShaderIrInst.Bra;
|
||||
|
|
|
@ -121,8 +121,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
int count = 0;
|
||||
|
||||
for (int index = 0; index < OmapTargets.Length; index++)
|
||||
for (int component = 0; component < 4; component++)
|
||||
if (OmapTargets[index].ComponentEnabled(component)) count++;
|
||||
{
|
||||
for (int component = 0; component < 4; component++)
|
||||
{
|
||||
if (OmapTargets[index].ComponentEnabled(component))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Depth register is always two registers after the last color output
|
||||
return count + 1;
|
||||
|
|
|
@ -35,7 +35,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public ShaderIrNode GetLastNode()
|
||||
{
|
||||
if (Nodes.Count > 0) return Nodes[Nodes.Count - 1];
|
||||
if (Nodes.Count > 0)
|
||||
{
|
||||
return Nodes[Nodes.Count - 1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -130,7 +130,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private static void Set(string encoding, ShaderDecodeFunc func)
|
||||
{
|
||||
if (encoding.Length != EncodingBits) throw new ArgumentException(nameof(encoding));
|
||||
if (encoding.Length != EncodingBits)
|
||||
{
|
||||
throw new ArgumentException(nameof(encoding));
|
||||
}
|
||||
|
||||
int bit = encoding.Length - 1;
|
||||
int value = 0;
|
||||
|
@ -163,9 +166,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
value &= xMask;
|
||||
|
||||
for (int x = 0; x < xBits; x++) value |= ((index >> x) & 1) << xPos[x];
|
||||
for (int x = 0; x < xBits; x++)
|
||||
{
|
||||
value |= ((index >> x) & 1) << xPos[x];
|
||||
}
|
||||
|
||||
if (_opCodes[value] == null || _opCodes[value].XBits > xBits) _opCodes[value] = entry;
|
||||
if (_opCodes[value] == null || _opCodes[value].XBits > xBits)
|
||||
{
|
||||
_opCodes[value] = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,10 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
internal void Enlarge(int newSize)
|
||||
{
|
||||
if (Size < newSize) Size = newSize;
|
||||
if (Size < newSize)
|
||||
{
|
||||
Size = newSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,10 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
public static void Dump(IGalMemory memory, long position, GalShaderType type, string extSuffix = "")
|
||||
{
|
||||
if (!IsDumpEnabled()) return;
|
||||
if (!IsDumpEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string fileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(type) + extSuffix + ".bin";
|
||||
|
||||
|
@ -26,7 +29,10 @@ namespace Ryujinx.Graphics.Gal
|
|||
BinaryWriter fullWriter = new BinaryWriter(fullFile);
|
||||
BinaryWriter codeWriter = new BinaryWriter(codeFile);
|
||||
|
||||
for (long i = 0; i < 0x50; i += 4) fullWriter.Write(memory.ReadInt32(position + i));
|
||||
for (long i = 0; i < 0x50; i += 4)
|
||||
{
|
||||
fullWriter.Write(memory.ReadInt32(position + i));
|
||||
}
|
||||
|
||||
long offset = 0;
|
||||
|
||||
|
@ -42,7 +48,10 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
//Zero instructions (other kind of NOP) stop immediatly,
|
||||
//this is to avoid two rows of zeroes
|
||||
if (instruction == 0) break;
|
||||
if (instruction == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fullWriter.Write(instruction);
|
||||
codeWriter.Write(instruction);
|
||||
|
@ -98,7 +107,10 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
private static string CreateAndReturn(string dir)
|
||||
{
|
||||
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
_uploadedKeys = new HashSet<long>[(int)NvGpuBufferType.Count];
|
||||
|
||||
for (int index = 0; index < _uploadedKeys.Length; index++) _uploadedKeys[index] = new HashSet<long>();
|
||||
for (int index = 0; index < _uploadedKeys.Length; index++)
|
||||
{
|
||||
_uploadedKeys[index] = new HashSet<long>();
|
||||
}
|
||||
|
||||
_imageTypes = new Dictionary<long, ImageType>();
|
||||
}
|
||||
|
@ -38,7 +41,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
_imageTypes[position] = ImageType.ColorBuffer;
|
||||
|
||||
if (!TryReuse(vmm, position, newImage)) _gpu.Renderer.Texture.Create(position, (int)size, newImage);
|
||||
if (!TryReuse(vmm, position, newImage))
|
||||
{
|
||||
_gpu.Renderer.Texture.Create(position, (int)size, newImage);
|
||||
}
|
||||
|
||||
_gpu.Renderer.RenderTarget.BindColor(position, attachment);
|
||||
}
|
||||
|
@ -49,7 +55,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
_imageTypes[position] = ImageType.ZetaBuffer;
|
||||
|
||||
if (!TryReuse(vmm, position, newImage)) _gpu.Renderer.Texture.Create(position, (int)size, newImage);
|
||||
if (!TryReuse(vmm, position, newImage))
|
||||
{
|
||||
_gpu.Renderer.Texture.Create(position, (int)size, newImage);
|
||||
}
|
||||
|
||||
_gpu.Renderer.RenderTarget.BindZeta(position);
|
||||
}
|
||||
|
@ -58,7 +67,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
PrepareSendTexture(vmm, position, newImage);
|
||||
|
||||
if (texIndex >= 0) _gpu.Renderer.Texture.Bind(position, texIndex, newImage);
|
||||
if (texIndex >= 0)
|
||||
{
|
||||
_gpu.Renderer.Texture.Bind(position, texIndex, newImage);
|
||||
}
|
||||
|
||||
_imageTypes[position] = ImageType.Texture;
|
||||
}
|
||||
|
@ -70,6 +82,7 @@ namespace Ryujinx.Graphics
|
|||
bool skipCheck = false;
|
||||
|
||||
if (_imageTypes.TryGetValue(position, out ImageType oldType))
|
||||
{
|
||||
if (oldType == ImageType.ColorBuffer || oldType == ImageType.ZetaBuffer)
|
||||
{
|
||||
//Avoid data destruction
|
||||
|
@ -77,9 +90,15 @@ namespace Ryujinx.Graphics
|
|||
|
||||
skipCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (skipCheck || !MemoryRegionModified(vmm, position, size, NvGpuBufferType.Texture))
|
||||
if (TryReuse(vmm, position, newImage)) return;
|
||||
{
|
||||
if (TryReuse(vmm, position, newImage))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] data = ImageUtils.ReadTexture(vmm, newImage, position);
|
||||
|
||||
|
@ -102,14 +121,20 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
HashSet<long> uploaded = _uploadedKeys[(int)type];
|
||||
|
||||
if (!uploaded.Add(position)) return false;
|
||||
if (!uploaded.Add(position))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return vmm.IsRegionModified(position, size, type);
|
||||
}
|
||||
|
||||
public void ClearPbCache()
|
||||
{
|
||||
for (int index = 0; index < _uploadedKeys.Length; index++) _uploadedKeys[index].Clear();
|
||||
for (int index = 0; index < _uploadedKeys.Length; index++)
|
||||
{
|
||||
_uploadedKeys[index].Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
FetchOpCode(mme);
|
||||
|
||||
while (Step(vmm, mme));
|
||||
while (Step(vmm, mme))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
//Due to the delay slot, we still need to execute
|
||||
//one more instruction before we actually exit.
|
||||
|
@ -88,7 +91,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
private void Reset()
|
||||
{
|
||||
for (int index = 0; index < _gprs.Length; index++) _gprs[index] = 0;
|
||||
for (int index = 0; index < _gprs.Length; index++)
|
||||
{
|
||||
_gprs[index] = 0;
|
||||
}
|
||||
|
||||
_methAddr = 0;
|
||||
_methIncr = 0;
|
||||
|
@ -207,7 +213,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
bool noDelays = (_opCode & 0x20) != 0;
|
||||
|
||||
if (noDelays) FetchOpCode(mme);
|
||||
if (noDelays)
|
||||
{
|
||||
FetchOpCode(mme);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -385,7 +394,12 @@ namespace Ryujinx.Graphics
|
|||
//If we don't have any parameters in the FIFO,
|
||||
//keep running the PFIFO engine until it writes the parameters.
|
||||
while (!Fifo.TryDequeue(out value))
|
||||
if (!_pFifo.Step()) return 0;
|
||||
{
|
||||
if (!_pFifo.Step())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -39,9 +39,12 @@ namespace Ryujinx.Graphics.Memory
|
|||
{
|
||||
case SubmissionMode.Incrementing:
|
||||
{
|
||||
for (int index = 0; index < args && CanRead(); index++, meth++) pushBuffer.Add(new NvGpuPBEntry(meth, subC, reader.ReadInt32()));
|
||||
for (int index = 0; index < args && CanRead(); index++, meth++)
|
||||
{
|
||||
pushBuffer.Add(new NvGpuPBEntry(meth, subC, reader.ReadInt32()));
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
case SubmissionMode.NonIncrementing:
|
||||
|
@ -50,9 +53,12 @@ namespace Ryujinx.Graphics.Memory
|
|||
|
||||
for (int index = 0; index < arguments.Length; index++)
|
||||
{
|
||||
if (!CanRead()) break;
|
||||
if (!CanRead())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
arguments[index] = reader.ReadInt32();
|
||||
arguments[index] = reader.ReadInt32();
|
||||
}
|
||||
|
||||
pushBuffer.Add(new NvGpuPBEntry(meth, subC, arguments));
|
||||
|
@ -69,15 +75,21 @@ namespace Ryujinx.Graphics.Memory
|
|||
|
||||
case SubmissionMode.IncrementOnce:
|
||||
{
|
||||
if (CanRead()) pushBuffer.Add(new NvGpuPBEntry(meth, subC, reader.ReadInt32()));
|
||||
if (CanRead())
|
||||
{
|
||||
pushBuffer.Add(new NvGpuPBEntry(meth, subC, reader.ReadInt32()));
|
||||
}
|
||||
|
||||
if (CanRead() && args > 1)
|
||||
if (CanRead() && args > 1)
|
||||
{
|
||||
int[] arguments = new int[args - 1];
|
||||
|
||||
for (int index = 0; index < arguments.Length && CanRead(); index++) arguments[index] = reader.ReadInt32();
|
||||
for (int index = 0; index < arguments.Length && CanRead(); index++)
|
||||
{
|
||||
arguments[index] = reader.ReadInt32();
|
||||
}
|
||||
|
||||
pushBuffer.Add(new NvGpuPBEntry(meth + 1, subC, arguments));
|
||||
pushBuffer.Add(new NvGpuPBEntry(meth + 1, subC, arguments));
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -45,7 +45,10 @@ namespace Ryujinx.Graphics.Memory
|
|||
{
|
||||
lock (_pageTable)
|
||||
{
|
||||
for (long offset = 0; offset < size; offset += PageSize) SetPte(va + offset, pa + offset);
|
||||
for (long offset = 0; offset < size; offset += PageSize)
|
||||
{
|
||||
SetPte(va + offset, pa + offset);
|
||||
}
|
||||
}
|
||||
|
||||
return va;
|
||||
|
@ -58,7 +61,12 @@ namespace Ryujinx.Graphics.Memory
|
|||
long va = GetFreePosition(size);
|
||||
|
||||
if (va != -1)
|
||||
for (long offset = 0; offset < size; offset += PageSize) SetPte(va + offset, pa + offset);
|
||||
{
|
||||
for (long offset = 0; offset < size; offset += PageSize)
|
||||
{
|
||||
SetPte(va + offset, pa + offset);
|
||||
}
|
||||
}
|
||||
|
||||
return va;
|
||||
}
|
||||
|
@ -69,9 +77,17 @@ namespace Ryujinx.Graphics.Memory
|
|||
lock (_pageTable)
|
||||
{
|
||||
for (long offset = 0; offset < size; offset += PageSize)
|
||||
if (IsPageInUse(va + offset)) return -1;
|
||||
{
|
||||
if (IsPageInUse(va + offset))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (long offset = 0; offset < size; offset += PageSize) SetPte(va + offset, PteReserved);
|
||||
for (long offset = 0; offset < size; offset += PageSize)
|
||||
{
|
||||
SetPte(va + offset, PteReserved);
|
||||
}
|
||||
}
|
||||
|
||||
return va;
|
||||
|
@ -84,7 +100,12 @@ namespace Ryujinx.Graphics.Memory
|
|||
long position = GetFreePosition(size, align);
|
||||
|
||||
if (position != -1)
|
||||
for (long offset = 0; offset < size; offset += PageSize) SetPte(position + offset, PteReserved);
|
||||
{
|
||||
for (long offset = 0; offset < size; offset += PageSize)
|
||||
{
|
||||
SetPte(position + offset, PteReserved);
|
||||
}
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
@ -94,7 +115,10 @@ namespace Ryujinx.Graphics.Memory
|
|||
{
|
||||
lock (_pageTable)
|
||||
{
|
||||
for (long offset = 0; offset < size; offset += PageSize) SetPte(va + offset, PteUnmapped);
|
||||
for (long offset = 0; offset < size; offset += PageSize)
|
||||
{
|
||||
SetPte(va + offset, PteUnmapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,16 +129,23 @@ namespace Ryujinx.Graphics.Memory
|
|||
long position = PageSize;
|
||||
long freeSize = 0;
|
||||
|
||||
if (align < 1) align = 1;
|
||||
if (align < 1)
|
||||
{
|
||||
align = 1;
|
||||
}
|
||||
|
||||
align = (align + PageMask) & ~PageMask;
|
||||
|
||||
while (position + freeSize < AddrSize)
|
||||
{
|
||||
if (!IsPageInUse(position + freeSize))
|
||||
{
|
||||
freeSize += PageSize;
|
||||
|
||||
if (freeSize >= size) return position;
|
||||
if (freeSize >= size)
|
||||
{
|
||||
return position;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -123,8 +154,12 @@ namespace Ryujinx.Graphics.Memory
|
|||
|
||||
long remainder = position % align;
|
||||
|
||||
if (remainder != 0) position = position - remainder + align;
|
||||
if (remainder != 0)
|
||||
{
|
||||
position = position - remainder + align;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -133,7 +168,10 @@ namespace Ryujinx.Graphics.Memory
|
|||
{
|
||||
long basePos = GetPte(va);
|
||||
|
||||
if (basePos < 0) return -1;
|
||||
if (basePos < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return basePos + (va & PageMask);
|
||||
}
|
||||
|
@ -141,19 +179,30 @@ namespace Ryujinx.Graphics.Memory
|
|||
public bool IsRegionFree(long va, long size)
|
||||
{
|
||||
for (long offset = 0; offset < size; offset += PageSize)
|
||||
if (IsPageInUse(va + offset)) return false;
|
||||
{
|
||||
if (IsPageInUse(va + offset))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsPageInUse(long va)
|
||||
{
|
||||
if (va >> (PtLvl0Bits + PtLvl1Bits + PtPageBits) != 0) return false;
|
||||
if (va >> (PtLvl0Bits + PtLvl1Bits + PtPageBits) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long l0 = (va >> PtLvl0Bit) & PtLvl0Mask;
|
||||
long l1 = (va >> PtLvl1Bit) & PtLvl1Mask;
|
||||
|
||||
if (_pageTable[l0] == null) return false;
|
||||
if (_pageTable[l0] == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _pageTable[l0][l1] != PteUnmapped;
|
||||
}
|
||||
|
@ -163,7 +212,10 @@ namespace Ryujinx.Graphics.Memory
|
|||
long l0 = (position >> PtLvl0Bit) & PtLvl0Mask;
|
||||
long l1 = (position >> PtLvl1Bit) & PtLvl1Mask;
|
||||
|
||||
if (_pageTable[l0] == null) return -1;
|
||||
if (_pageTable[l0] == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _pageTable[l0][l1];
|
||||
}
|
||||
|
@ -177,7 +229,10 @@ namespace Ryujinx.Graphics.Memory
|
|||
{
|
||||
_pageTable[l0] = new long[PtLvl1Size];
|
||||
|
||||
for (int index = 0; index < PtLvl1Size; index++) _pageTable[l0][index] = PteUnmapped;
|
||||
for (int index = 0; index < PtLvl1Size; index++)
|
||||
{
|
||||
_pageTable[l0][index] = PteUnmapped;
|
||||
}
|
||||
}
|
||||
|
||||
_pageTable[l0][l1] = tgtAddr;
|
||||
|
|
|
@ -55,16 +55,26 @@ namespace Ryujinx.Graphics.Memory
|
|||
long rgEnd = Math.Min(current.End, newCached.End);
|
||||
|
||||
if ((current.Value & mask) == 0)
|
||||
{
|
||||
_cachedRanges.Add(new ValueRange<int>(rgStart, rgEnd, current.Value | mask));
|
||||
}
|
||||
else
|
||||
{
|
||||
coverage += rgEnd - rgStart;
|
||||
}
|
||||
|
||||
if (rgStart > lastEnd) _cachedRanges.Add(new ValueRange<int>(lastEnd, rgStart, mask));
|
||||
if (rgStart > lastEnd)
|
||||
{
|
||||
_cachedRanges.Add(new ValueRange<int>(lastEnd, rgStart, mask));
|
||||
}
|
||||
|
||||
lastEnd = rgEnd;
|
||||
}
|
||||
|
||||
if (lastEnd < newCached.End) _cachedRanges.Add(new ValueRange<int>(lastEnd, newCached.End, mask));
|
||||
if (lastEnd < newCached.End)
|
||||
{
|
||||
_cachedRanges.Add(new ValueRange<int>(lastEnd, newCached.End, mask));
|
||||
}
|
||||
|
||||
return coverage != size;
|
||||
}
|
||||
|
|
|
@ -48,9 +48,13 @@ namespace Ryujinx.Graphics
|
|||
public void CallMethod(NvGpuVmm vmm, NvGpuPBEntry pbEntry)
|
||||
{
|
||||
if (_methods.TryGetValue(pbEntry.Method, out NvGpuMethod method))
|
||||
{
|
||||
method(vmm, pbEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteRegister(pbEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void TextureCopy(NvGpuVmm vmm, NvGpuPBEntry pbEntry)
|
||||
|
@ -134,7 +138,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
int argsCount = pbEntry.Arguments.Count;
|
||||
|
||||
if (argsCount > 0) Registers[pbEntry.Method] = pbEntry.Arguments[argsCount - 1];
|
||||
if (argsCount > 0)
|
||||
{
|
||||
Registers[pbEntry.Method] = pbEntry.Arguments[argsCount - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadRegister(NvGpuEngine2dReg reg)
|
||||
|
|
|
@ -53,11 +53,17 @@ namespace Ryujinx.Graphics
|
|||
|
||||
_constBuffers = new ConstBuffer[6][];
|
||||
|
||||
for (int index = 0; index < _constBuffers.Length; index++) _constBuffers[index] = new ConstBuffer[18];
|
||||
for (int index = 0; index < _constBuffers.Length; index++)
|
||||
{
|
||||
_constBuffers[index] = new ConstBuffer[18];
|
||||
}
|
||||
|
||||
_uploadedKeys = new List<long>[(int)NvGpuBufferType.Count];
|
||||
|
||||
for (int i = 0; i < _uploadedKeys.Length; i++) _uploadedKeys[i] = new List<long>();
|
||||
for (int i = 0; i < _uploadedKeys.Length; i++)
|
||||
{
|
||||
_uploadedKeys[i] = new List<long>();
|
||||
}
|
||||
|
||||
//Ensure that all components are enabled by default.
|
||||
//FIXME: Is this correct?
|
||||
|
@ -67,14 +73,21 @@ namespace Ryujinx.Graphics
|
|||
public void CallMethod(NvGpuVmm vmm, NvGpuPBEntry pbEntry)
|
||||
{
|
||||
if (_methods.TryGetValue(pbEntry.Method, out NvGpuMethod method))
|
||||
{
|
||||
method(vmm, pbEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteRegister(pbEntry);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetCache()
|
||||
{
|
||||
foreach (List<long> uploaded in _uploadedKeys) uploaded.Clear();
|
||||
foreach (List<long> uploaded in _uploadedKeys)
|
||||
{
|
||||
uploaded.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void VertexEndGl(NvGpuVmm vmm, NvGpuPBEntry pbEntry)
|
||||
|
@ -92,7 +105,10 @@ namespace Ryujinx.Graphics
|
|||
SetColorMask(state);
|
||||
SetPrimitiveRestart(state);
|
||||
|
||||
for (int fbIndex = 0; fbIndex < 8; fbIndex++) SetFrameBuffer(vmm, fbIndex);
|
||||
for (int fbIndex = 0; fbIndex < 8; fbIndex++)
|
||||
{
|
||||
SetFrameBuffer(vmm, fbIndex);
|
||||
}
|
||||
|
||||
SetZeta(vmm);
|
||||
|
||||
|
@ -328,11 +344,13 @@ namespace Ryujinx.Graphics
|
|||
|
||||
//Flipping breaks facing. Flipping front facing too fixes it
|
||||
if (signX != signY)
|
||||
{
|
||||
switch (frontFace)
|
||||
{
|
||||
case GalFrontFace.Cw: frontFace = GalFrontFace.Ccw; break;
|
||||
case GalFrontFace.Ccw: frontFace = GalFrontFace.Cw; break;
|
||||
}
|
||||
}
|
||||
|
||||
state.FrontFace = frontFace;
|
||||
}
|
||||
|
@ -341,7 +359,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
state.CullFaceEnabled = ReadRegisterBool(NvGpuEngine3dReg.CullFaceEnable);
|
||||
|
||||
if (state.CullFaceEnabled) state.CullFace = (GalCullFace)ReadRegister(NvGpuEngine3dReg.CullFace);
|
||||
if (state.CullFaceEnabled)
|
||||
{
|
||||
state.CullFace = (GalCullFace)ReadRegister(NvGpuEngine3dReg.CullFace);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDepth(GalPipelineState state)
|
||||
|
@ -350,7 +371,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
state.DepthWriteEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthWriteEnable);
|
||||
|
||||
if (state.DepthTestEnabled) state.DepthFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.DepthTestFunction);
|
||||
if (state.DepthTestEnabled)
|
||||
{
|
||||
state.DepthFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.DepthTestFunction);
|
||||
}
|
||||
|
||||
state.DepthRangeNear = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNNear);
|
||||
state.DepthRangeFar = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNFar);
|
||||
|
@ -419,7 +443,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
state.PrimitiveRestartEnabled = ReadRegisterBool(NvGpuEngine3dReg.PrimRestartEnable);
|
||||
|
||||
if (state.PrimitiveRestartEnabled) state.PrimitiveRestartIndex = (uint)ReadRegister(NvGpuEngine3dReg.PrimRestartIndex);
|
||||
if (state.PrimitiveRestartEnabled)
|
||||
{
|
||||
state.PrimitiveRestartIndex = (uint)ReadRegister(NvGpuEngine3dReg.PrimRestartIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetRenderTargets()
|
||||
|
@ -459,14 +486,19 @@ namespace Ryujinx.Graphics
|
|||
int texIndex = 0;
|
||||
|
||||
for (int index = 0; index < keys.Length; index++)
|
||||
{
|
||||
foreach (ShaderDeclInfo declInfo in _gpu.Renderer.Shader.GetTextureUsage(keys[index]))
|
||||
{
|
||||
long position;
|
||||
|
||||
if (declInfo.IsCb)
|
||||
{
|
||||
position = _constBuffers[index][declInfo.Cbuf].Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = _constBuffers[index][textureCbIndex].Position;
|
||||
}
|
||||
|
||||
int textureHandle = vmm.ReadInt32(position + declInfo.Index * 4);
|
||||
|
||||
|
@ -474,11 +506,15 @@ namespace Ryujinx.Graphics
|
|||
|
||||
texIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UploadTexture(NvGpuVmm vmm, int texIndex, int textureHandle)
|
||||
{
|
||||
if (textureHandle == 0) return;
|
||||
if (textureHandle == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int ticIndex = (textureHandle >> 0) & 0xfffff;
|
||||
int tscIndex = (textureHandle >> 20) & 0xfff;
|
||||
|
@ -496,12 +532,20 @@ namespace Ryujinx.Graphics
|
|||
long key = vmm.ReadInt64(ticPosition + 4) & 0xffffffffffff;
|
||||
|
||||
if (image.Layout == GalMemoryLayout.BlockLinear)
|
||||
{
|
||||
key &= ~0x1ffL;
|
||||
else if (image.Layout == GalMemoryLayout.Pitch) key &= ~0x1fL;
|
||||
}
|
||||
else if (image.Layout == GalMemoryLayout.Pitch)
|
||||
{
|
||||
key &= ~0x1fL;
|
||||
}
|
||||
|
||||
key = vmm.GetPhysicalAddress(key);
|
||||
|
||||
if (key == -1) return;
|
||||
if (key == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_gpu.ResourceManager.SendTexture(vmm, key, image, texIndex);
|
||||
|
||||
|
@ -511,11 +555,15 @@ namespace Ryujinx.Graphics
|
|||
private void UploadConstBuffers(NvGpuVmm vmm, GalPipelineState state, long[] keys)
|
||||
{
|
||||
for (int stage = 0; stage < keys.Length; stage++)
|
||||
{
|
||||
foreach (ShaderDeclInfo declInfo in _gpu.Renderer.Shader.GetConstBufferUsage(keys[stage]))
|
||||
{
|
||||
ConstBuffer cb = _constBuffers[stage][declInfo.Cbuf];
|
||||
|
||||
if (!cb.Enabled) continue;
|
||||
if (!cb.Enabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
long key = vmm.GetPhysicalAddress(cb.Position);
|
||||
|
||||
|
@ -528,6 +576,7 @@ namespace Ryujinx.Graphics
|
|||
|
||||
state.ConstBufferKeys[stage][declInfo.Cbuf] = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UploadVertexArrays(NvGpuVmm vmm, GalPipelineState state)
|
||||
|
@ -546,7 +595,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
int indexEntrySize = 1 << indexEntryFmt;
|
||||
|
||||
if (indexEntrySize > 4) throw new InvalidOperationException();
|
||||
if (indexEntrySize > 4)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (indexCount != 0)
|
||||
{
|
||||
|
@ -571,9 +623,13 @@ namespace Ryujinx.Graphics
|
|||
byte[] buffer = vmm.ReadBytes(ibPosition, ibSize);
|
||||
|
||||
if (primType == GalPrimitiveType.Quads)
|
||||
{
|
||||
buffer = QuadHelper.ConvertIbQuadsToTris(buffer, indexEntrySize, indexCount);
|
||||
}
|
||||
else /* if (PrimType == GalPrimitiveType.QuadStrip) */
|
||||
{
|
||||
buffer = QuadHelper.ConvertIbQuadStripToTris(buffer, indexEntrySize, indexCount);
|
||||
}
|
||||
|
||||
_gpu.Renderer.Rasterizer.CreateIbo(iboKey, ibSize, buffer);
|
||||
}
|
||||
|
@ -586,9 +642,13 @@ namespace Ryujinx.Graphics
|
|||
else
|
||||
{
|
||||
if (primType == GalPrimitiveType.Quads)
|
||||
{
|
||||
_gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertIbSizeQuadsToTris(ibSize), indexFormat);
|
||||
}
|
||||
else /* if (PrimType == GalPrimitiveType.QuadStrip) */
|
||||
{
|
||||
_gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertIbSizeQuadStripToTris(ibSize), indexFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -600,7 +660,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
int arrayIndex = packed & 0x1f;
|
||||
|
||||
if (attribs[arrayIndex] == null) attribs[arrayIndex] = new List<GalVertexAttrib>();
|
||||
if (attribs[arrayIndex] == null)
|
||||
{
|
||||
attribs[arrayIndex] = new List<GalVertexAttrib>();
|
||||
}
|
||||
|
||||
long vertexPosition = MakeInt64From2XInt32(NvGpuEngine3dReg.VertexArrayNAddress + arrayIndex * 4);
|
||||
|
||||
|
@ -624,13 +687,19 @@ namespace Ryujinx.Graphics
|
|||
|
||||
for (int index = 0; index < 32; index++)
|
||||
{
|
||||
if (attribs[index] == null) continue;
|
||||
if (attribs[index] == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int control = ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + index * 4);
|
||||
|
||||
bool enable = (control & 0x1000) != 0;
|
||||
|
||||
if (!enable) continue;
|
||||
if (!enable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
long vertexPosition = MakeInt64From2XInt32(NvGpuEngine3dReg.VertexArrayNAddress + index * 4);
|
||||
long vertexEndPos = MakeInt64From2XInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + index * 2);
|
||||
|
@ -641,9 +710,15 @@ namespace Ryujinx.Graphics
|
|||
|
||||
int stride = control & 0xfff;
|
||||
|
||||
if (instanced && vertexDivisor != 0) vertexPosition += stride * (_currentInstance / vertexDivisor);
|
||||
if (instanced && vertexDivisor != 0)
|
||||
{
|
||||
vertexPosition += stride * (_currentInstance / vertexDivisor);
|
||||
}
|
||||
|
||||
if (vertexPosition > vertexEndPos) continue;
|
||||
if (vertexPosition > vertexEndPos)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
long vboKey = vmm.GetPhysicalAddress(vertexPosition);
|
||||
|
||||
|
@ -677,11 +752,19 @@ namespace Ryujinx.Graphics
|
|||
bool instanceNext = ((primCtrl >> 26) & 1) != 0;
|
||||
bool instanceCont = ((primCtrl >> 27) & 1) != 0;
|
||||
|
||||
if (instanceNext && instanceCont) throw new InvalidOperationException("GPU tried to increase and reset instance count at the same time");
|
||||
if (instanceNext && instanceCont)
|
||||
{
|
||||
throw new InvalidOperationException("GPU tried to increase and reset instance count at the same time");
|
||||
}
|
||||
|
||||
if (instanceNext)
|
||||
{
|
||||
_currentInstance++;
|
||||
else if (!instanceCont) _currentInstance = 0;
|
||||
}
|
||||
else if (!instanceCont)
|
||||
{
|
||||
_currentInstance = 0;
|
||||
}
|
||||
|
||||
state.Instance = _currentInstance;
|
||||
|
||||
|
@ -711,9 +794,13 @@ namespace Ryujinx.Graphics
|
|||
//vertex of a quad, if it points to the middle of a
|
||||
//quad (First % 4 != 0 for Quads) then it will not work properly.
|
||||
if (primType == GalPrimitiveType.Quads)
|
||||
{
|
||||
indexFirst = QuadHelper.ConvertIbSizeQuadsToTris(indexFirst);
|
||||
}
|
||||
else /* if (PrimType == GalPrimitiveType.QuadStrip) */
|
||||
{
|
||||
indexFirst = QuadHelper.ConvertIbSizeQuadStripToTris(indexFirst);
|
||||
}
|
||||
}
|
||||
|
||||
_gpu.Renderer.Rasterizer.DrawElements(iboKey, indexFirst, vertexBase, primType);
|
||||
|
@ -804,7 +891,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
int size = ReadRegister(NvGpuEngine3dReg.ConstBufferSize);
|
||||
|
||||
if (!_gpu.Renderer.Buffer.IsCached(cbKey, size)) _gpu.Renderer.Buffer.Create(cbKey, size);
|
||||
if (!_gpu.Renderer.Buffer.IsCached(cbKey, size))
|
||||
{
|
||||
_gpu.Renderer.Buffer.Create(cbKey, size);
|
||||
}
|
||||
|
||||
ConstBuffer cb = _constBuffers[stage][index];
|
||||
|
||||
|
@ -832,7 +922,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
int argsCount = pbEntry.Arguments.Count;
|
||||
|
||||
if (argsCount > 0) Registers[pbEntry.Method] = pbEntry.Arguments[argsCount - 1];
|
||||
if (argsCount > 0)
|
||||
{
|
||||
Registers[pbEntry.Method] = pbEntry.Arguments[argsCount - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadRegister(NvGpuEngine3dReg reg)
|
||||
|
@ -859,7 +952,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
List<long> uploaded = _uploadedKeys[(int)type];
|
||||
|
||||
if (uploaded.Contains(key)) return false;
|
||||
if (uploaded.Contains(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uploaded.Add(key);
|
||||
|
||||
|
|
|
@ -36,9 +36,13 @@ namespace Ryujinx.Graphics
|
|||
public void CallMethod(NvGpuVmm vmm, NvGpuPBEntry pbEntry)
|
||||
{
|
||||
if (_methods.TryGetValue(pbEntry.Method, out NvGpuMethod method))
|
||||
{
|
||||
method(vmm, pbEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteRegister(pbEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void Execute(NvGpuVmm vmm, NvGpuPBEntry pbEntry)
|
||||
|
@ -92,9 +96,15 @@ namespace Ryujinx.Graphics
|
|||
|
||||
if (copy2D)
|
||||
{
|
||||
if (srcLinear) srcPosX = srcPosY = srcPosZ = 0;
|
||||
if (srcLinear)
|
||||
{
|
||||
srcPosX = srcPosY = srcPosZ = 0;
|
||||
}
|
||||
|
||||
if (dstLinear) dstPosX = dstPosY = dstPosZ = 0;
|
||||
if (dstLinear)
|
||||
{
|
||||
dstPosX = dstPosY = dstPosZ = 0;
|
||||
}
|
||||
|
||||
if (srcLinear && dstLinear)
|
||||
{
|
||||
|
@ -114,19 +124,28 @@ namespace Ryujinx.Graphics
|
|||
ISwizzle srcSwizzle;
|
||||
|
||||
if (srcLinear)
|
||||
{
|
||||
srcSwizzle = new LinearSwizzle(srcPitch, srcCpp);
|
||||
}
|
||||
else
|
||||
{
|
||||
srcSwizzle = new BlockLinearSwizzle(srcSizeX, srcCpp, srcBlockHeight);
|
||||
}
|
||||
|
||||
ISwizzle dstSwizzle;
|
||||
|
||||
if (dstLinear)
|
||||
{
|
||||
dstSwizzle = new LinearSwizzle(dstPitch, dstCpp);
|
||||
}
|
||||
else
|
||||
{
|
||||
dstSwizzle = new BlockLinearSwizzle(dstSizeX, dstCpp, dstBlockHeight);
|
||||
}
|
||||
|
||||
for (int y = 0; y < yCount; y++)
|
||||
for (int x = 0; x < xCount; x++)
|
||||
{
|
||||
for (int x = 0; x < xCount; x++)
|
||||
{
|
||||
int srcOffset = srcSwizzle.GetSwizzleOffset(srcPosX + x, srcPosY + y);
|
||||
int dstOffset = dstSwizzle.GetSwizzleOffset(dstPosX + x, dstPosY + y);
|
||||
|
@ -136,6 +155,7 @@ namespace Ryujinx.Graphics
|
|||
|
||||
vmm.Memory.CopyBytes(src, dst, srcCpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -155,7 +175,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
int argsCount = pbEntry.Arguments.Count;
|
||||
|
||||
if (argsCount > 0) Registers[pbEntry.Method] = pbEntry.Arguments[argsCount - 1];
|
||||
if (argsCount > 0)
|
||||
{
|
||||
Registers[pbEntry.Method] = pbEntry.Arguments[argsCount - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadRegister(NvGpuEngineM2mfReg reg)
|
||||
|
|
|
@ -39,9 +39,13 @@ namespace Ryujinx.Graphics
|
|||
public void CallMethod(NvGpuVmm vmm, NvGpuPBEntry pbEntry)
|
||||
{
|
||||
if (_methods.TryGetValue(pbEntry.Method, out NvGpuMethod method))
|
||||
{
|
||||
method(vmm, pbEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteRegister(pbEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void Execute(NvGpuVmm vmm, NvGpuPBEntry pbEntry)
|
||||
|
@ -57,7 +61,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
_gpu.Fifo.Step();
|
||||
|
||||
for (int offset = 0; offset < lineLengthIn; offset += 4) vmm.WriteInt32(dstAddress + offset, _dataBuffer[offset >> 2]);
|
||||
for (int offset = 0; offset < lineLengthIn; offset += 4)
|
||||
{
|
||||
vmm.WriteInt32(dstAddress + offset, _dataBuffer[offset >> 2]);
|
||||
}
|
||||
}
|
||||
|
||||
private void PushData(NvGpuVmm vmm, NvGpuPBEntry pbEntry)
|
||||
|
@ -76,7 +83,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
int argsCount = pbEntry.Arguments.Count;
|
||||
|
||||
if (argsCount > 0) Registers[pbEntry.Method] = pbEntry.Arguments[argsCount - 1];
|
||||
if (argsCount > 0)
|
||||
{
|
||||
Registers[pbEntry.Method] = pbEntry.Arguments[argsCount - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadRegister(NvGpuEngineP2mfReg reg)
|
||||
|
|
|
@ -76,7 +76,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
public void DispatchCalls()
|
||||
{
|
||||
while (Step());
|
||||
while (Step())
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private (NvGpuVmm Vmm, NvGpuPBEntry[] Pb) _curr;
|
||||
|
@ -87,7 +90,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
while (_curr.Pb == null || _curr.Pb.Length <= _currPbEntryIndex)
|
||||
{
|
||||
if (!_bufferQueue.TryDequeue(out _curr)) return false;
|
||||
if (!_bufferQueue.TryDequeue(out _curr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_gpu.Engine3D.ResetCache();
|
||||
|
||||
|
@ -141,8 +147,12 @@ namespace Ryujinx.Graphics
|
|||
|
||||
case NvGpuFifoMeth.SendMacroCodeData:
|
||||
{
|
||||
foreach (int arg in pbEntry.Arguments) _mme[_currMacroPosition++] = arg;
|
||||
break;
|
||||
foreach (int arg in pbEntry.Arguments)
|
||||
{
|
||||
_mme[_currMacroPosition++] = arg;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NvGpuFifoMeth.SetMacroBindingIndex:
|
||||
|
@ -171,9 +181,16 @@ namespace Ryujinx.Graphics
|
|||
int macroIndex = (pbEntry.Method >> 1) & MacroIndexMask;
|
||||
|
||||
if ((pbEntry.Method & 1) != 0)
|
||||
foreach (int arg in pbEntry.Arguments) _macros[macroIndex].PushParam(arg);
|
||||
{
|
||||
foreach (int arg in pbEntry.Arguments)
|
||||
{
|
||||
_macros[macroIndex].PushParam(arg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_macros[macroIndex].Execute(vmm, _mme, pbEntry.Arguments[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
// How many indices do we have?
|
||||
int indices = Height * Width;
|
||||
|
||||
if (DualPlane) indices *= 2;
|
||||
if (DualPlane)
|
||||
{
|
||||
indices *= 2;
|
||||
}
|
||||
|
||||
IntegerEncoded intEncoded = IntegerEncoded.CreateEncoding(MaxWeight);
|
||||
|
||||
|
@ -40,7 +43,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
int ret = Width * Height;
|
||||
|
||||
if (DualPlane) ret *= 2;
|
||||
if (DualPlane)
|
||||
{
|
||||
ret *= 2;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -59,16 +65,23 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
BinaryReader binReader = new BinaryReader(inputStream);
|
||||
|
||||
if (blockX > 12 || blockY > 12) throw new ASTCDecoderException("Block size unsupported!");
|
||||
if (blockX > 12 || blockY > 12)
|
||||
{
|
||||
throw new ASTCDecoderException("Block size unsupported!");
|
||||
}
|
||||
|
||||
if (blockZ != 1 || z != 1) throw new ASTCDecoderException("3D compressed textures unsupported!");
|
||||
if (blockZ != 1 || z != 1)
|
||||
{
|
||||
throw new ASTCDecoderException("3D compressed textures unsupported!");
|
||||
}
|
||||
|
||||
using (MemoryStream outputStream = new MemoryStream())
|
||||
{
|
||||
int blockIndex = 0;
|
||||
|
||||
for (int j = 0; j < y; j += blockY)
|
||||
for (int i = 0; i < x; i += blockX)
|
||||
{
|
||||
for (int i = 0; i < x; i += blockX)
|
||||
{
|
||||
int[] decompressedData = new int[144];
|
||||
|
||||
|
@ -90,6 +103,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
blockIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return outputStream.ToArray();
|
||||
}
|
||||
|
@ -105,7 +119,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
BitArrayStream bitStream = new BitArrayStream(new BitArray(inputBuffer));
|
||||
TexelWeightParams texelParams = DecodeBlockInfo(bitStream);
|
||||
|
||||
if (texelParams.Error) throw new ASTCDecoderException("Invalid block mode");
|
||||
if (texelParams.Error)
|
||||
{
|
||||
throw new ASTCDecoderException("Invalid block mode");
|
||||
}
|
||||
|
||||
if (texelParams.VoidExtentLdr)
|
||||
{
|
||||
|
@ -114,17 +131,29 @@ namespace Ryujinx.Graphics.Texture
|
|||
return true;
|
||||
}
|
||||
|
||||
if (texelParams.VoidExtentHdr) throw new ASTCDecoderException("HDR void extent blocks are unsupported!");
|
||||
if (texelParams.VoidExtentHdr)
|
||||
{
|
||||
throw new ASTCDecoderException("HDR void extent blocks are unsupported!");
|
||||
}
|
||||
|
||||
if (texelParams.Width > blockWidth) throw new ASTCDecoderException("Texel weight grid width should be smaller than block width");
|
||||
if (texelParams.Width > blockWidth)
|
||||
{
|
||||
throw new ASTCDecoderException("Texel weight grid width should be smaller than block width");
|
||||
}
|
||||
|
||||
if (texelParams.Height > blockHeight) throw new ASTCDecoderException("Texel weight grid height should be smaller than block height");
|
||||
if (texelParams.Height > blockHeight)
|
||||
{
|
||||
throw new ASTCDecoderException("Texel weight grid height should be smaller than block height");
|
||||
}
|
||||
|
||||
// Read num partitions
|
||||
int numberPartitions = bitStream.ReadBits(2) + 1;
|
||||
Debug.Assert(numberPartitions <= 4);
|
||||
|
||||
if (numberPartitions == 4 && texelParams.DualPlane) throw new ASTCDecoderException("Dual plane mode is incompatible with four partition blocks");
|
||||
if (numberPartitions == 4 && texelParams.DualPlane)
|
||||
{
|
||||
throw new ASTCDecoderException("Dual plane mode is incompatible with four partition blocks");
|
||||
}
|
||||
|
||||
// Based on the number of partitions, read the color endpoint mode for
|
||||
// each partition.
|
||||
|
@ -160,6 +189,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
uint extraColorEndpointModeBits = 0;
|
||||
|
||||
if (baseMode != 0)
|
||||
{
|
||||
switch (numberPartitions)
|
||||
{
|
||||
case 2: extraColorEndpointModeBits += 2; break;
|
||||
|
@ -167,13 +197,17 @@ namespace Ryujinx.Graphics.Texture
|
|||
case 4: extraColorEndpointModeBits += 8; break;
|
||||
default: Debug.Assert(false); break;
|
||||
}
|
||||
}
|
||||
|
||||
remainingBits -= (int)extraColorEndpointModeBits;
|
||||
|
||||
// Do we have a dual plane situation?
|
||||
int planeSelectorBits = 0;
|
||||
|
||||
if (texelParams.DualPlane) planeSelectorBits = 2;
|
||||
if (texelParams.DualPlane)
|
||||
{
|
||||
planeSelectorBits = 2;
|
||||
}
|
||||
|
||||
remainingBits -= planeSelectorBits;
|
||||
|
||||
|
@ -218,7 +252,11 @@ namespace Ryujinx.Graphics.Texture
|
|||
for (int i = 0; i < numberPartitions; i++)
|
||||
{
|
||||
colorEndpointMode[i] = baseMode;
|
||||
if (!c[i]) colorEndpointMode[i] -= 1;
|
||||
if (!c[i])
|
||||
{
|
||||
colorEndpointMode[i] -= 1;
|
||||
}
|
||||
|
||||
colorEndpointMode[i] <<= 2;
|
||||
colorEndpointMode[i] |= m[i];
|
||||
}
|
||||
|
@ -227,11 +265,18 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
uint tempColorEndpointMode = baseColorEndpointMode >> 2;
|
||||
|
||||
for (uint i = 0; i < numberPartitions; i++) colorEndpointMode[i] = tempColorEndpointMode;
|
||||
for (uint i = 0; i < numberPartitions; i++)
|
||||
{
|
||||
colorEndpointMode[i] = tempColorEndpointMode;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure everything up till here is sane.
|
||||
for (int i = 0; i < numberPartitions; i++) Debug.Assert(colorEndpointMode[i] < 16);
|
||||
for (int i = 0; i < numberPartitions; i++)
|
||||
{
|
||||
Debug.Assert(colorEndpointMode[i] < 16);
|
||||
}
|
||||
|
||||
Debug.Assert(bitStream.Position + texelParams.GetPackedBitSize() == 128);
|
||||
|
||||
// Decode both color data and texel weight data
|
||||
|
@ -246,7 +291,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
int colorValuesPosition = 0;
|
||||
|
||||
for (int i = 0; i < numberPartitions; i++) ComputeEndpoints(endPoints[i], colorValues, colorEndpointMode[i], ref colorValuesPosition);
|
||||
for (int i = 0; i < numberPartitions; i++)
|
||||
{
|
||||
ComputeEndpoints(endPoints[i], colorValues, colorEndpointMode[i], ref colorValuesPosition);
|
||||
}
|
||||
|
||||
// Read the texel weight data.
|
||||
byte[] texelWeightData = (byte[])inputBuffer.Clone();
|
||||
|
@ -266,7 +314,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
texelWeightData[clearByteStart - 1] &= (byte)((1 << (texelParams.GetPackedBitSize() % 8)) - 1);
|
||||
|
||||
int cLen = 16 - clearByteStart;
|
||||
for (int i = clearByteStart; i < clearByteStart + cLen; i++) texelWeightData[i] = 0;
|
||||
for (int i = clearByteStart; i < clearByteStart + cLen; i++)
|
||||
{
|
||||
texelWeightData[i] = 0;
|
||||
}
|
||||
|
||||
List<IntegerEncoded> texelWeightValues = new List<IntegerEncoded>();
|
||||
BitArrayStream weightBitStream = new BitArrayStream(new BitArray(texelWeightData));
|
||||
|
@ -283,7 +334,8 @@ namespace Ryujinx.Graphics.Texture
|
|||
// Now that we have endpoints and weights, we can interpolate and generate
|
||||
// the proper decoding...
|
||||
for (int j = 0; j < blockHeight; j++)
|
||||
for (int i = 0; i < blockWidth; i++)
|
||||
{
|
||||
for (int i = 0; i < blockWidth; i++)
|
||||
{
|
||||
int partition = Select2DPartition(partitionIndex, i, j, numberPartitions, blockHeight * blockWidth < 32);
|
||||
Debug.Assert(partition < numberPartitions);
|
||||
|
@ -298,9 +350,12 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
int plane = 0;
|
||||
|
||||
if (texelParams.DualPlane && ((planeIndices + 1) & 3) == component) plane = 1;
|
||||
if (texelParams.DualPlane && ((planeIndices + 1) & 3) == component)
|
||||
{
|
||||
plane = 1;
|
||||
}
|
||||
|
||||
int weight = weights[plane][j * blockWidth + i];
|
||||
int weight = weights[plane][j * blockWidth + i];
|
||||
int finalComponent = (component0 * (64 - weight) + component1 * weight + 32) / 64;
|
||||
|
||||
if (finalComponent == 65535)
|
||||
|
@ -316,6 +371,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
outputBuffer[j * blockWidth + i] = pixel.Pack();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -327,7 +383,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
private static int SelectPartition(int seed, int x, int y, int z, int partitionCount, bool isSmallBlock)
|
||||
{
|
||||
if (partitionCount == 1) return 0;
|
||||
if (partitionCount == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isSmallBlock)
|
||||
{
|
||||
|
@ -385,12 +444,29 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
a &= 0x3F; b &= 0x3F; c &= 0x3F; d &= 0x3F;
|
||||
|
||||
if (partitionCount < 4) d = 0;
|
||||
if (partitionCount < 3) c = 0;
|
||||
if (partitionCount < 4)
|
||||
{
|
||||
d = 0;
|
||||
}
|
||||
|
||||
if (partitionCount < 3)
|
||||
{
|
||||
c = 0;
|
||||
}
|
||||
|
||||
if (a >= b && a >= c && a >= d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (b >= c && b >= d)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (c >= d)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (a >= b && a >= c && a >= d) return 0;
|
||||
else if (b >= c && b >= d) return 1;
|
||||
else if (c >= d) return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -424,10 +500,16 @@ namespace Ryujinx.Graphics.Texture
|
|||
i++;
|
||||
unquantized[1][weightIndices] = UnquantizeTexelWeight(weights[i]);
|
||||
|
||||
if (i == weights.Count) break;
|
||||
if (i == weights.Count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (++weightIndices >= texelParams.Width * texelParams.Height) break;
|
||||
if (++weightIndices >= texelParams.Width * texelParams.Height)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Do infill if necessary (Section C.2.18) ...
|
||||
|
@ -437,8 +519,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
int planeScale = texelParams.DualPlane ? 2 : 1;
|
||||
|
||||
for (int plane = 0; plane < planeScale; plane++)
|
||||
for (int t = 0; t < blockHeight; t++)
|
||||
for (int s = 0; s < blockWidth; s++)
|
||||
{
|
||||
for (int t = 0; t < blockHeight; t++)
|
||||
{
|
||||
for (int s = 0; s < blockWidth; s++)
|
||||
{
|
||||
int cs = ds * s;
|
||||
int ct = dt * t;
|
||||
|
@ -464,15 +548,29 @@ namespace Ryujinx.Graphics.Texture
|
|||
int p10 = 0;
|
||||
int p11 = 0;
|
||||
|
||||
if (v0 < texelParams.Width * texelParams.Height) p00 = unquantized[plane][v0];
|
||||
if (v0 < texelParams.Width * texelParams.Height)
|
||||
{
|
||||
p00 = unquantized[plane][v0];
|
||||
}
|
||||
|
||||
if (v0 + 1 < texelParams.Width * texelParams.Height) p01 = unquantized[plane][v0 + 1];
|
||||
if (v0 + 1 < texelParams.Width * texelParams.Height)
|
||||
{
|
||||
p01 = unquantized[plane][v0 + 1];
|
||||
}
|
||||
|
||||
if (v0 + texelParams.Width < texelParams.Width * texelParams.Height) p10 = unquantized[plane][v0 + texelParams.Width];
|
||||
if (v0 + texelParams.Width < texelParams.Width * texelParams.Height)
|
||||
{
|
||||
p10 = unquantized[plane][v0 + texelParams.Width];
|
||||
}
|
||||
|
||||
if (v0 + texelParams.Width + 1 < texelParams.Width * texelParams.Height) p11 = unquantized[plane][v0 + texelParams.Width + 1];
|
||||
if (v0 + texelParams.Width + 1 < texelParams.Width * texelParams.Height)
|
||||
{
|
||||
p11 = unquantized[plane][v0 + texelParams.Width + 1];
|
||||
}
|
||||
|
||||
outputBuffer[plane][t * blockWidth + s] = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4;
|
||||
outputBuffer[plane][t * blockWidth + s] = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,7 +686,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
Debug.Assert(result < 64);
|
||||
|
||||
// Change from [0,63] to [0,64]
|
||||
if (result > 32) result += 1;
|
||||
if (result > 32)
|
||||
{
|
||||
result += 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -603,7 +704,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
uint[] ret = new uint[number];
|
||||
|
||||
for (int i = 0; i < number; i++) ret[i] = (uint)colorValues[colorValuesPosition++];
|
||||
for (int i = 0; i < number; i++)
|
||||
{
|
||||
ret[i] = (uint)colorValues[colorValuesPosition++];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -612,7 +716,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
int[] ret = new int[number];
|
||||
|
||||
for (int i = 0; i < number; i++) ret[i] = colorValues[colorValuesPosition++];
|
||||
for (int i = 0; i < number; i++)
|
||||
{
|
||||
ret[i] = colorValues[colorValuesPosition++];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -796,7 +903,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
// First figure out how many color values we have
|
||||
int numberValues = 0;
|
||||
|
||||
for (int i = 0; i < numberPartitions; i++) numberValues += (int)((modes[i] >> 2) + 1) << 1;
|
||||
for (int i = 0; i < numberPartitions; i++)
|
||||
{
|
||||
numberValues += (int)((modes[i] >> 2) + 1) << 1;
|
||||
}
|
||||
|
||||
// Then based on the number of values and the remaining number of bits,
|
||||
// figure out the max value for each of them...
|
||||
|
@ -813,7 +923,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
while (--range > 0)
|
||||
{
|
||||
IntegerEncoded newIntEncoded = IntegerEncoded.CreateEncoding(range);
|
||||
if (!newIntEncoded.MatchesEncoding(intEncoded)) break;
|
||||
if (!newIntEncoded.MatchesEncoding(intEncoded))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return to last matching range.
|
||||
|
@ -994,13 +1107,19 @@ namespace Ryujinx.Graphics.Texture
|
|||
}
|
||||
|
||||
// Make sure that each of our values is in the proper range...
|
||||
for (int i = 0; i < numberValues; i++) Debug.Assert(outputValues[i] <= 255);
|
||||
for (int i = 0; i < numberValues; i++)
|
||||
{
|
||||
Debug.Assert(outputValues[i] <= 255);
|
||||
}
|
||||
}
|
||||
|
||||
private static void FillVoidExtentLdr(BitArrayStream bitStream, int[] outputBuffer, int blockWidth, int blockHeight)
|
||||
{
|
||||
// Don't actually care about the void extent, just read the bits...
|
||||
for (int i = 0; i < 4; ++i) bitStream.ReadBits(13);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
bitStream.ReadBits(13);
|
||||
}
|
||||
|
||||
// Decode the RGBA components and renormalize them to the range [0, 255]
|
||||
ushort r = (ushort)bitStream.ReadBits(16);
|
||||
|
@ -1011,7 +1130,12 @@ namespace Ryujinx.Graphics.Texture
|
|||
int rgba = (r >> 8) | (g & 0xFF00) | ((b & 0xFF00) << 8) | ((a & 0xFF00) << 16);
|
||||
|
||||
for (int j = 0; j < blockHeight; j++)
|
||||
for (int i = 0; i < blockWidth; i++) outputBuffer[j * blockWidth + i] = rgba;
|
||||
{
|
||||
for (int i = 0; i < blockWidth; i++)
|
||||
{
|
||||
outputBuffer[j * blockWidth + i] = rgba;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TexelWeightParams DecodeBlockInfo(BitArrayStream bitStream)
|
||||
|
@ -1025,12 +1149,19 @@ namespace Ryujinx.Graphics.Texture
|
|||
if ((modeBits & 0x01FF) == 0x1FC)
|
||||
{
|
||||
if ((modeBits & 0x200) != 0)
|
||||
{
|
||||
texelParams.VoidExtentHdr = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
texelParams.VoidExtentLdr = true;
|
||||
}
|
||||
|
||||
// Next two bits must be one.
|
||||
if ((modeBits & 0x400) == 0 || bitStream.ReadBits(1) == 0) texelParams.Error = true;
|
||||
if ((modeBits & 0x400) == 0 || bitStream.ReadBits(1) == 0)
|
||||
{
|
||||
texelParams.Error = true;
|
||||
}
|
||||
|
||||
return texelParams;
|
||||
}
|
||||
|
@ -1067,9 +1198,13 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
// layout is in [3-4]
|
||||
if ((modeBits & 0x100) != 0)
|
||||
{
|
||||
layout = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
layout = 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1080,9 +1215,13 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
// layout is in [0-1]
|
||||
if ((modeBits & 0x4) != 0)
|
||||
{
|
||||
layout = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
layout = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1097,9 +1236,13 @@ namespace Ryujinx.Graphics.Texture
|
|||
Debug.Assert((modeBits & 0x40) == 0);
|
||||
|
||||
if ((modeBits & 0x20) != 0)
|
||||
{
|
||||
layout = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
layout = 7;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1110,9 +1253,13 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
// layout is in [5-6]
|
||||
if ((modeBits & 0x80) != 0)
|
||||
{
|
||||
layout = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
layout = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1121,9 +1268,13 @@ namespace Ryujinx.Graphics.Texture
|
|||
// Determine R
|
||||
int r = (modeBits >> 4) & 1;
|
||||
if (layout < 5)
|
||||
{
|
||||
r |= (modeBits & 0x3) << 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
r |= (modeBits & 0xC) >> 1;
|
||||
}
|
||||
|
||||
Debug.Assert(2 <= r && r <= 7);
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@ namespace Ryujinx.Graphics.Texture
|
|||
B = b;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
_bitDepth[i] = 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClampByte()
|
||||
|
|
|
@ -19,7 +19,12 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
int retValue = 0;
|
||||
for (int i = Position; i < Position + length; i++)
|
||||
if (BitsArray[i]) retValue |= 1 << (i - Position);
|
||||
{
|
||||
if (BitsArray[i])
|
||||
{
|
||||
retValue |= 1 << (i - Position);
|
||||
}
|
||||
}
|
||||
|
||||
Position += length;
|
||||
return (short)retValue;
|
||||
|
@ -29,7 +34,12 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
int retValue = 0;
|
||||
for (int i = start; i <= end; i++)
|
||||
if (BitsArray[i]) retValue |= 1 << (i - start);
|
||||
{
|
||||
if (BitsArray[i])
|
||||
{
|
||||
retValue |= 1 << (i - start);
|
||||
}
|
||||
}
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
@ -41,7 +51,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
public void WriteBits(int value, int length)
|
||||
{
|
||||
for (int i = Position; i < Position + length; i++) BitsArray[i] = ((value >> (i - Position)) & 1) != 0;
|
||||
for (int i = Position; i < Position + length; i++)
|
||||
{
|
||||
BitsArray[i] = ((value >> (i - Position)) & 1) != 0;
|
||||
}
|
||||
|
||||
Position += length;
|
||||
}
|
||||
|
@ -55,8 +68,15 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
public static int Replicate(int value, int numberBits, int toBit)
|
||||
{
|
||||
if (numberBits == 0) return 0;
|
||||
if (toBit == 0) return 0;
|
||||
if (numberBits == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (toBit == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tempValue = value & ((1 << numberBits) - 1);
|
||||
int retValue = tempValue;
|
||||
|
@ -81,7 +101,11 @@ namespace Ryujinx.Graphics.Texture
|
|||
public static int PopCnt(int number)
|
||||
{
|
||||
int counter;
|
||||
for (counter = 0; number != 0; counter++) number &= number - 1;
|
||||
for (counter = 0; number != 0; counter++)
|
||||
{
|
||||
number &= number - 1;
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
@ -99,7 +123,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
b |= a & 0x80;
|
||||
a >>= 1;
|
||||
a &= 0x3F;
|
||||
if ((a & 0x20) != 0) a -= 0x40;
|
||||
if ((a & 0x20) != 0)
|
||||
{
|
||||
a -= 0x40;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
int count = 0;
|
||||
|
||||
while (((value >> count) & 1) == 0) count++;
|
||||
while (((value >> count) & 1) == 0)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -144,15 +144,24 @@ namespace Ryujinx.Graphics.Texture
|
|||
GalTextureType aType,
|
||||
bool convSrgb)
|
||||
{
|
||||
if (rType != gType || rType != bType || rType != aType) throw new NotImplementedException("Per component types are not implemented!");
|
||||
if (rType != gType || rType != bType || rType != aType)
|
||||
{
|
||||
throw new NotImplementedException("Per component types are not implemented!");
|
||||
}
|
||||
|
||||
if (!_textureTable.TryGetValue(format, out GalImageFormat imageFormat)) throw new NotImplementedException($"Format 0x{(int)format:x} not implemented!");
|
||||
if (!_textureTable.TryGetValue(format, out GalImageFormat imageFormat))
|
||||
{
|
||||
throw new NotImplementedException($"Format 0x{(int)format:x} not implemented!");
|
||||
}
|
||||
|
||||
GalImageFormat formatType = convSrgb ? Srgb : GetFormatType(rType);
|
||||
|
||||
GalImageFormat combinedFormat = (imageFormat & GalImageFormat.FormatMask) | formatType;
|
||||
|
||||
if (!imageFormat.HasFlag(formatType)) throw new NotImplementedException($"Format \"{combinedFormat}\" not implemented!");
|
||||
if (!imageFormat.HasFlag(formatType))
|
||||
{
|
||||
throw new NotImplementedException($"Format \"{combinedFormat}\" not implemented!");
|
||||
}
|
||||
|
||||
return combinedFormat;
|
||||
}
|
||||
|
@ -212,9 +221,13 @@ namespace Ryujinx.Graphics.Texture
|
|||
AMemory cpuMemory;
|
||||
|
||||
if (memory is NvGpuVmm vmm)
|
||||
{
|
||||
cpuMemory = vmm.Memory;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpuMemory = (AMemory)memory;
|
||||
}
|
||||
|
||||
ISwizzle swizzle = TextureHelper.GetSwizzle(image);
|
||||
|
||||
|
@ -259,7 +272,8 @@ namespace Ryujinx.Graphics.Texture
|
|||
int inOffs = 0;
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
long offset = (uint)swizzle.GetSwizzleOffset(x, y);
|
||||
|
||||
|
@ -267,6 +281,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
inOffs += bytesPerPixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetSize(GalImage image)
|
||||
|
@ -307,9 +322,13 @@ namespace Ryujinx.Graphics.Texture
|
|||
int alignMask;
|
||||
|
||||
if (image.Layout == GalMemoryLayout.BlockLinear)
|
||||
{
|
||||
alignMask = image.TileWidth * (64 / desc.BytesPerPixel) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
alignMask = 32 / desc.BytesPerPixel - 1;
|
||||
}
|
||||
|
||||
return (image.Width + alignMask) & ~alignMask;
|
||||
}
|
||||
|
@ -358,7 +377,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
GalImageFormat pixelFormat = format & GalImageFormat.FormatMask;
|
||||
|
||||
if (_imageTable.TryGetValue(pixelFormat, out ImageDescriptor descriptor)) return descriptor;
|
||||
if (_imageTable.TryGetValue(pixelFormat, out ImageDescriptor descriptor))
|
||||
{
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
throw new NotImplementedException($"Format \"{pixelFormat}\" not implemented!");
|
||||
}
|
||||
|
|
|
@ -41,8 +41,14 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
int totalBits = NumberBits * numberVals;
|
||||
if (_encoding == EIntegerEncoding.Trit)
|
||||
{
|
||||
totalBits += (numberVals * 8 + 4) / 5;
|
||||
else if (_encoding == EIntegerEncoding.Quint) totalBits += (numberVals * 7 + 2) / 3;
|
||||
}
|
||||
else if (_encoding == EIntegerEncoding.Quint)
|
||||
{
|
||||
totalBits += (numberVals * 7 + 2) / 3;
|
||||
}
|
||||
|
||||
return totalBits;
|
||||
}
|
||||
|
||||
|
@ -53,13 +59,22 @@ namespace Ryujinx.Graphics.Texture
|
|||
int check = maxVal + 1;
|
||||
|
||||
// Is maxVal a power of two?
|
||||
if ((check & (check - 1)) == 0) return new IntegerEncoded(EIntegerEncoding.JustBits, BitArrayStream.PopCnt(maxVal));
|
||||
if ((check & (check - 1)) == 0)
|
||||
{
|
||||
return new IntegerEncoded(EIntegerEncoding.JustBits, BitArrayStream.PopCnt(maxVal));
|
||||
}
|
||||
|
||||
// Is maxVal of the type 3*2^n - 1?
|
||||
if (check % 3 == 0 && ((check / 3) & (check / 3 - 1)) == 0) return new IntegerEncoded(EIntegerEncoding.Trit, BitArrayStream.PopCnt(check / 3 - 1));
|
||||
if (check % 3 == 0 && ((check / 3) & (check / 3 - 1)) == 0)
|
||||
{
|
||||
return new IntegerEncoded(EIntegerEncoding.Trit, BitArrayStream.PopCnt(check / 3 - 1));
|
||||
}
|
||||
|
||||
// Is maxVal of the type 5*2^n - 1?
|
||||
if (check % 5 == 0 && ((check / 5) & (check / 5 - 1)) == 0) return new IntegerEncoded(EIntegerEncoding.Quint, BitArrayStream.PopCnt(check / 5 - 1));
|
||||
if (check % 5 == 0 && ((check / 5) & (check / 5 - 1)) == 0)
|
||||
{
|
||||
return new IntegerEncoded(EIntegerEncoding.Quint, BitArrayStream.PopCnt(check / 5 - 1));
|
||||
}
|
||||
|
||||
// Apparently it can't be represented with a bounded integer sequence...
|
||||
// just iterate.
|
||||
|
@ -221,6 +236,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
// Start decoding
|
||||
int numberValuesDecoded = 0;
|
||||
while (numberValuesDecoded < numberValues)
|
||||
{
|
||||
switch (intEncoded.GetEncoding())
|
||||
{
|
||||
case EIntegerEncoding.Quint:
|
||||
|
@ -248,6 +264,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,13 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
if (swizzle == TextureSwizzle.BlockLinear ||
|
||||
swizzle == TextureSwizzle.BlockLinearColorKey)
|
||||
{
|
||||
layout = GalMemoryLayout.BlockLinear;
|
||||
}
|
||||
else
|
||||
{
|
||||
layout = GalMemoryLayout.Pitch;
|
||||
}
|
||||
|
||||
int blockHeightLog2 = (tic[3] >> 3) & 7;
|
||||
int tileWidthLog2 = (tic[3] >> 10) & 7;
|
||||
|
@ -48,7 +52,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
zSource,
|
||||
wSource);
|
||||
|
||||
if (layout == GalMemoryLayout.Pitch) image.Pitch = (tic[3] & 0xffff) << 5;
|
||||
if (layout == GalMemoryLayout.Pitch)
|
||||
{
|
||||
image.Pitch = (tic[3] & 0xffff) << 5;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
@ -99,7 +106,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
int[] words = new int[count];
|
||||
|
||||
for (int index = 0; index < count; index++, position += 4) words[index] = vmm.ReadInt32(position);
|
||||
for (int index = 0; index < count; index++, position += 4)
|
||||
{
|
||||
words[index] = vmm.ReadInt32(position);
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,10 @@ namespace Ryujinx.Graphics.Texture
|
|||
IAMemory memory,
|
||||
long position)
|
||||
{
|
||||
if (memory is NvGpuVmm vmm) return (vmm.Memory, vmm.GetPhysicalAddress(position));
|
||||
if (memory is NvGpuVmm vmm)
|
||||
{
|
||||
return (vmm.Memory, vmm.GetPhysicalAddress(position));
|
||||
}
|
||||
|
||||
return ((AMemory)memory, position);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,10 @@ namespace Ryujinx.Graphics
|
|||
|
||||
public void Add(ValueRange<T> range)
|
||||
{
|
||||
if (range.End <= range.Start) return;
|
||||
if (range.End <= range.Start)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int first = BinarySearchFirstIntersection(range);
|
||||
|
||||
|
@ -25,9 +28,13 @@ namespace Ryujinx.Graphics
|
|||
int gtIndex = BinarySearchGt(range);
|
||||
|
||||
if (gtIndex != -1)
|
||||
{
|
||||
_ranges.Insert(gtIndex, range);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ranges.Add(range);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -82,7 +89,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
int first = BinarySearchFirstIntersection(range);
|
||||
|
||||
if (first == -1) return;
|
||||
if (first == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
(int start, int end) = GetAllIntersectionRanges(range, first);
|
||||
|
||||
|
@ -98,13 +108,19 @@ namespace Ryujinx.Graphics
|
|||
private void InsertNextNeighbour(int index, ValueRange<T> range, ValueRange<T> next)
|
||||
{
|
||||
//Split last intersection (ordered by Start) if necessary.
|
||||
if (range.End < next.End) InsertNewRange(index, range.End, next.End, next.Value);
|
||||
if (range.End < next.End)
|
||||
{
|
||||
InsertNewRange(index, range.End, next.End, next.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertPrevNeighbour(int index, ValueRange<T> range, ValueRange<T> prev)
|
||||
{
|
||||
//Split first intersection (ordered by Start) if necessary.
|
||||
if (range.Start > prev.Start) InsertNewRange(index, prev.Start, range.Start, prev.Value);
|
||||
if (range.Start > prev.Start)
|
||||
{
|
||||
InsertNewRange(index, prev.Start, range.Start, prev.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertNewRange(int index, long start, long end, T value)
|
||||
|
@ -116,7 +132,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
int first = BinarySearchFirstIntersection(range);
|
||||
|
||||
if (first == -1) return new ValueRange<T>[0];
|
||||
if (first == -1)
|
||||
{
|
||||
return new ValueRange<T>[0];
|
||||
}
|
||||
|
||||
(int start, int end) = GetAllIntersectionRanges(range, first);
|
||||
|
||||
|
@ -128,9 +147,15 @@ namespace Ryujinx.Graphics
|
|||
int start = baseIndex;
|
||||
int end = baseIndex;
|
||||
|
||||
while (start > 0 && Intersects(range, _ranges[start - 1])) start--;
|
||||
while (start > 0 && Intersects(range, _ranges[start - 1]))
|
||||
{
|
||||
start--;
|
||||
}
|
||||
|
||||
while (end < _ranges.Count - 1 && Intersects(range, _ranges[end + 1])) end++;
|
||||
while (end < _ranges.Count - 1 && Intersects(range, _ranges[end + 1]))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
return (start, end);
|
||||
}
|
||||
|
@ -148,12 +173,19 @@ namespace Ryujinx.Graphics
|
|||
|
||||
ValueRange<T> current = _ranges[middle];
|
||||
|
||||
if (Intersects(range, current)) return middle;
|
||||
if (Intersects(range, current))
|
||||
{
|
||||
return middle;
|
||||
}
|
||||
|
||||
if (range.Start < current.Start)
|
||||
{
|
||||
right = middle - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -178,7 +210,10 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
right = middle - 1;
|
||||
|
||||
if (gtIndex == -1 || current.Start < _ranges[gtIndex].Start) gtIndex = middle;
|
||||
if (gtIndex == -1 || current.Start < _ranges[gtIndex].Start)
|
||||
{
|
||||
gtIndex = middle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -28,7 +28,12 @@ namespace Ryujinx.HLE.FileSystem
|
|||
baseSavePath = Path.Combine(baseSavePath, "save");
|
||||
|
||||
if (saveMetaData.TitleId == 0 && saveMetaData.SaveDataType == SaveDataType.SaveData)
|
||||
if (context.Process.MetaData != null) currentTitleId = context.Process.MetaData.Aci0.TitleId;
|
||||
{
|
||||
if (context.Process.MetaData != null)
|
||||
{
|
||||
currentTitleId = context.Process.MetaData.Aci0.TitleId;
|
||||
}
|
||||
}
|
||||
|
||||
string saveAccount = saveMetaData.UserId.IsZero() ? "savecommon" : saveMetaData.UserId.ToString();
|
||||
|
||||
|
|
|
@ -30,15 +30,24 @@ namespace Ryujinx.HLE.FileSystem
|
|||
public string GetFullPath(string basePath, string fileName)
|
||||
{
|
||||
if (fileName.StartsWith("//"))
|
||||
{
|
||||
fileName = fileName.Substring(2);
|
||||
}
|
||||
else if (fileName.StartsWith('/'))
|
||||
{
|
||||
fileName = fileName.Substring(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string fullPath = Path.GetFullPath(Path.Combine(basePath, fileName));
|
||||
|
||||
if (!fullPath.StartsWith(GetBasePath())) return null;
|
||||
if (!fullPath.StartsWith(GetBasePath()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
|
@ -66,7 +75,11 @@ namespace Ryujinx.HLE.FileSystem
|
|||
public string SwitchPathToSystemPath(string switchPath)
|
||||
{
|
||||
string[] parts = switchPath.Split(":");
|
||||
if (parts.Length != 2) return null;
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return GetFullPath(MakeDirAndGetFullPath(parts[0]), parts[1]);
|
||||
}
|
||||
|
||||
|
@ -77,7 +90,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
string rawPath = systemPath.Replace(baseSystemPath, "");
|
||||
int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar);
|
||||
if (firstSeparatorOffset == -1) return $"{rawPath}:/";
|
||||
if (firstSeparatorOffset == -1)
|
||||
{
|
||||
return $"{rawPath}:/";
|
||||
}
|
||||
|
||||
string basePath = rawPath.Substring(0, firstSeparatorOffset);
|
||||
string fileName = rawPath.Substring(firstSeparatorOffset + 1);
|
||||
|
@ -90,7 +106,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
string fullPath = Path.Combine(GetBasePath(), dir);
|
||||
|
||||
if (!Directory.Exists(fullPath)) Directory.CreateDirectory(fullPath);
|
||||
if (!Directory.Exists(fullPath))
|
||||
{
|
||||
Directory.CreateDirectory(fullPath);
|
||||
}
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
|
@ -114,7 +133,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing) RomFs?.Dispose();
|
||||
if (disposing)
|
||||
{
|
||||
RomFs?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,8 +43,13 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
writer.Write("[");
|
||||
|
||||
if (_dimensionString != null)
|
||||
{
|
||||
writer.Write(_dimensionString);
|
||||
else if (_dimensionExpression != null) _dimensionExpression.Print(writer);
|
||||
}
|
||||
else if (_dimensionExpression != null)
|
||||
{
|
||||
_dimensionExpression.Print(writer);
|
||||
}
|
||||
|
||||
writer.Write("]");
|
||||
|
||||
|
|
|
@ -71,7 +71,10 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
{
|
||||
PrintLeft(writer);
|
||||
|
||||
if (HasRightPart()) PrintRight(writer);
|
||||
if (HasRightPart())
|
||||
{
|
||||
PrintRight(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void PrintLeft(TextWriter writer);
|
||||
|
|
|
@ -17,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
|
||||
public override void PrintLeft(TextWriter writer)
|
||||
{
|
||||
if (_name.Equals(">")) writer.Write("(");
|
||||
if (_name.Equals(">"))
|
||||
{
|
||||
writer.Write("(");
|
||||
}
|
||||
|
||||
writer.Write("(");
|
||||
_leftPart.Print(writer);
|
||||
|
@ -29,7 +32,10 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
_rightPart.Print(writer);
|
||||
writer.Write(")");
|
||||
|
||||
if (_name.Equals(">")) writer.Write(")");
|
||||
if (_name.Equals(">"))
|
||||
{
|
||||
writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,7 +29,10 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
_element.Print(writer);
|
||||
}
|
||||
|
||||
if (!_expression.GetType().Equals(NodeType.BracedExpression) || !_expression.GetType().Equals(NodeType.BracedRangeExpression)) writer.Write(" = ");
|
||||
if (!_expression.GetType().Equals(NodeType.BracedExpression) || !_expression.GetType().Equals(NodeType.BracedRangeExpression))
|
||||
{
|
||||
writer.Write(" = ");
|
||||
}
|
||||
|
||||
_expression.Print(writer);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue