mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-06-28 06:46:24 +02:00
Move solution and projects to src
This commit is contained in:
parent
cd124bda58
commit
cee7121058
3466 changed files with 55 additions and 55 deletions
8
src/Ryujinx.Tests/.runsettings
Normal file
8
src/Ryujinx.Tests/.runsettings
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RunSettings>
|
||||
<RunConfiguration>
|
||||
<EnvironmentVariables>
|
||||
<COMPlus_EnableAlternateStackCheck>1</COMPlus_EnableAlternateStackCheck>
|
||||
</EnvironmentVariables>
|
||||
</RunConfiguration>
|
||||
</RunSettings>
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer
|
||||
{
|
||||
class AudioRendererConfigurationTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x34, Unsafe.SizeOf<AudioRendererConfiguration>());
|
||||
}
|
||||
}
|
||||
}
|
16
src/Ryujinx.Tests/Audio/Renderer/BehaviourParameterTests.cs
Normal file
16
src/Ryujinx.Tests/Audio/Renderer/BehaviourParameterTests.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer
|
||||
{
|
||||
class BehaviourParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x10, Unsafe.SizeOf<BehaviourParameter>());
|
||||
Assert.AreEqual(0x10, Unsafe.SizeOf<BehaviourParameter.ErrorInfo>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer
|
||||
{
|
||||
class BiquadFilterParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0xC, Unsafe.SizeOf<BiquadFilterParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Common
|
||||
{
|
||||
class UpdateDataHeaderTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x40, Unsafe.SizeOf<UpdateDataHeader>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Common
|
||||
{
|
||||
class VoiceUpdateStateTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.LessOrEqual(Unsafe.SizeOf<VoiceUpdateState>(), 0x100);
|
||||
}
|
||||
}
|
||||
}
|
15
src/Ryujinx.Tests/Audio/Renderer/Common/WaveBufferTests.cs
Normal file
15
src/Ryujinx.Tests/Audio/Renderer/Common/WaveBufferTests.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Common
|
||||
{
|
||||
class WaveBufferTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x30, Unsafe.SizeOf<WaveBuffer>());
|
||||
}
|
||||
}
|
||||
}
|
93
src/Ryujinx.Tests/Audio/Renderer/Dsp/ResamplerTests.cs
Normal file
93
src/Ryujinx.Tests/Audio/Renderer/Dsp/ResamplerTests.cs
Normal file
|
@ -0,0 +1,93 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Dsp;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Audio.Renderer.Server.Upsampler;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Dsp
|
||||
{
|
||||
class ResamplerTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase(VoiceInParameter.SampleRateConversionQuality.Low)]
|
||||
[TestCase(VoiceInParameter.SampleRateConversionQuality.Default)]
|
||||
[TestCase(VoiceInParameter.SampleRateConversionQuality.High)]
|
||||
public void TestResamplerConsistencyUpsampling(VoiceInParameter.SampleRateConversionQuality quality)
|
||||
{
|
||||
DoResamplingTest(44100, 48000, quality);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(VoiceInParameter.SampleRateConversionQuality.Low)]
|
||||
[TestCase(VoiceInParameter.SampleRateConversionQuality.Default)]
|
||||
[TestCase(VoiceInParameter.SampleRateConversionQuality.High)]
|
||||
public void TestResamplerConsistencyDownsampling(VoiceInParameter.SampleRateConversionQuality quality)
|
||||
{
|
||||
DoResamplingTest(48000, 44100, quality);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a 1-second sine wave sample at input rate, resamples it to output rate, and
|
||||
/// ensures that it resampled at the expected rate with no discontinuities
|
||||
/// </summary>
|
||||
/// <param name="inputRate">The input sample rate to test</param>
|
||||
/// <param name="outputRate">The output sample rate to test</param>
|
||||
/// <param name="quality">The resampler quality to use</param>
|
||||
private static void DoResamplingTest(int inputRate, int outputRate, VoiceInParameter.SampleRateConversionQuality quality)
|
||||
{
|
||||
float inputSampleRate = (float)inputRate;
|
||||
float outputSampleRate = (float)outputRate;
|
||||
int inputSampleCount = inputRate;
|
||||
int outputSampleCount = outputRate;
|
||||
short[] inputBuffer = new short[inputSampleCount + 100]; // add some safety buffer at the end
|
||||
float[] outputBuffer = new float[outputSampleCount + 100];
|
||||
for (int sample = 0; sample < inputBuffer.Length; sample++)
|
||||
{
|
||||
// 440 hz sine wave with amplitude = 0.5f at input sample rate
|
||||
inputBuffer[sample] = (short)(32767 * MathF.Sin((440 / inputSampleRate) * (float)sample * MathF.PI * 2f) * 0.5f);
|
||||
}
|
||||
|
||||
float fraction = 0;
|
||||
|
||||
ResamplerHelper.Resample(
|
||||
outputBuffer.AsSpan(),
|
||||
inputBuffer.AsSpan(),
|
||||
inputSampleRate / outputSampleRate,
|
||||
ref fraction,
|
||||
outputSampleCount,
|
||||
quality,
|
||||
false);
|
||||
|
||||
float[] expectedOutput = new float[outputSampleCount];
|
||||
float sumDifference = 0;
|
||||
int delay = quality switch
|
||||
{
|
||||
VoiceInParameter.SampleRateConversionQuality.High => 3,
|
||||
VoiceInParameter.SampleRateConversionQuality.Default => 1,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
for (int sample = 0; sample < outputSampleCount; sample++)
|
||||
{
|
||||
outputBuffer[sample] /= 32767;
|
||||
// 440 hz sine wave with amplitude = 0.5f at output sample rate
|
||||
expectedOutput[sample] = MathF.Sin((440 / outputSampleRate) * (float)(sample + delay) * MathF.PI * 2f) * 0.5f;
|
||||
float thisDelta = Math.Abs(expectedOutput[sample] - outputBuffer[sample]);
|
||||
|
||||
// Ensure no discontinuities
|
||||
Assert.IsTrue(thisDelta < 0.1f);
|
||||
sumDifference += thisDelta;
|
||||
}
|
||||
|
||||
sumDifference = sumDifference / (float)outputSampleCount;
|
||||
// Expect the output to be 99% similar to the expected resampled sine wave
|
||||
Assert.IsTrue(sumDifference < 0.01f);
|
||||
}
|
||||
}
|
||||
}
|
64
src/Ryujinx.Tests/Audio/Renderer/Dsp/UpsamplerTests.cs
Normal file
64
src/Ryujinx.Tests/Audio/Renderer/Dsp/UpsamplerTests.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Dsp;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Audio.Renderer.Server.Upsampler;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Dsp
|
||||
{
|
||||
class UpsamplerTests
|
||||
{
|
||||
[Test]
|
||||
public void TestUpsamplerConsistency()
|
||||
{
|
||||
UpsamplerBufferState bufferState = new UpsamplerBufferState();
|
||||
int inputBlockSize = 160;
|
||||
int numInputSamples = 32000;
|
||||
int numOutputSamples = 48000;
|
||||
float inputSampleRate = numInputSamples;
|
||||
float outputSampleRate = numOutputSamples;
|
||||
float[] inputBuffer = new float[numInputSamples + 100];
|
||||
float[] outputBuffer = new float[numOutputSamples + 100];
|
||||
for (int sample = 0; sample < inputBuffer.Length; sample++)
|
||||
{
|
||||
// 440 hz sine wave with amplitude = 0.5f at input sample rate
|
||||
inputBuffer[sample] = MathF.Sin((440 / inputSampleRate) * (float)sample * MathF.PI * 2f) * 0.5f;
|
||||
}
|
||||
|
||||
int inputIdx = 0;
|
||||
int outputIdx = 0;
|
||||
while (inputIdx + inputBlockSize < numInputSamples)
|
||||
{
|
||||
int outputBufLength = (int)Math.Round((float)(inputIdx + inputBlockSize) * outputSampleRate / inputSampleRate) - outputIdx;
|
||||
UpsamplerHelper.Upsample(
|
||||
outputBuffer.AsSpan(outputIdx),
|
||||
inputBuffer.AsSpan(inputIdx),
|
||||
outputBufLength,
|
||||
inputBlockSize,
|
||||
ref bufferState);
|
||||
|
||||
inputIdx += inputBlockSize;
|
||||
outputIdx += outputBufLength;
|
||||
}
|
||||
|
||||
float[] expectedOutput = new float[numOutputSamples];
|
||||
float sumDifference = 0;
|
||||
for (int sample = 0; sample < numOutputSamples; sample++)
|
||||
{
|
||||
// 440 hz sine wave with amplitude = 0.5f at output sample rate with an offset of 15
|
||||
expectedOutput[sample] = MathF.Sin((440 / outputSampleRate) * (float)(sample - 15) * MathF.PI * 2f) * 0.5f;
|
||||
sumDifference += Math.Abs(expectedOutput[sample] - outputBuffer[sample]);
|
||||
}
|
||||
|
||||
sumDifference = sumDifference / (float)expectedOutput.Length;
|
||||
// Expect the output to be 98% similar to the expected resampled sine wave
|
||||
Assert.IsTrue(sumDifference < 0.02f);
|
||||
}
|
||||
}
|
||||
}
|
16
src/Ryujinx.Tests/Audio/Renderer/EffectInfoParameterTests.cs
Normal file
16
src/Ryujinx.Tests/Audio/Renderer/EffectInfoParameterTests.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer
|
||||
{
|
||||
class EffectInfoParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0xC0, Unsafe.SizeOf<EffectInParameterVersion1>());
|
||||
Assert.AreEqual(0xC0, Unsafe.SizeOf<EffectInParameterVersion2>());
|
||||
}
|
||||
}
|
||||
}
|
16
src/Ryujinx.Tests/Audio/Renderer/EffectOutStatusTests.cs
Normal file
16
src/Ryujinx.Tests/Audio/Renderer/EffectOutStatusTests.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer
|
||||
{
|
||||
class EffectOutStatusTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x10, Unsafe.SizeOf<EffectOutStatusVersion1>());
|
||||
Assert.AreEqual(0x90, Unsafe.SizeOf<EffectOutStatusVersion2>());
|
||||
}
|
||||
}
|
||||
}
|
16
src/Ryujinx.Tests/Audio/Renderer/MemoryPoolParameterTests.cs
Normal file
16
src/Ryujinx.Tests/Audio/Renderer/MemoryPoolParameterTests.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer
|
||||
{
|
||||
class MemoryPoolParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x20, Unsafe.SizeOf<MemoryPoolInParameter>());
|
||||
Assert.AreEqual(0x10, Unsafe.SizeOf<MemoryPoolOutStatus>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter
|
||||
{
|
||||
class BehaviourErrorInfoOutStatusTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0xB0, Unsafe.SizeOf<BehaviourErrorInfoOutStatus>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
class AuxParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x6C, Unsafe.SizeOf<AuxiliaryBufferParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
class BiquadFilterEffectParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x18, Unsafe.SizeOf<BiquadFilterEffectParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
class BufferMixerParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x94, Unsafe.SizeOf<BufferMixParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
class CompressorParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x38, Unsafe.SizeOf<CompressorParameter>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
class DelayParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x35, Unsafe.SizeOf<DelayParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
class LimiterParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x44, Unsafe.SizeOf<LimiterParameter>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
class LimiterStatisticsTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x30, Unsafe.SizeOf<LimiterStatistics>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
class Reverb3dParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x49, Unsafe.SizeOf<Reverb3dParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
class ReverbParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x41, Unsafe.SizeOf<ReverbParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter
|
||||
{
|
||||
class MixInParameterDirtyOnlyUpdateTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x20, Unsafe.SizeOf<MixInParameterDirtyOnlyUpdate>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter
|
||||
{
|
||||
class MixParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x930, Unsafe.SizeOf<MixParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Performance;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter
|
||||
{
|
||||
class PerformanceInParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x10, Unsafe.SizeOf<PerformanceInParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Performance;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter
|
||||
{
|
||||
class PerformanceOutStatusTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x10, Unsafe.SizeOf<PerformanceOutStatus>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter
|
||||
{
|
||||
class RendererInfoOutStatusTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x10, Unsafe.SizeOf<RendererInfoOutStatus>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Sink
|
||||
{
|
||||
class CircularBufferParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x24, Unsafe.SizeOf<CircularBufferParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter.Sink
|
||||
{
|
||||
class DeviceParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x11C, Unsafe.SizeOf<DeviceParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter
|
||||
{
|
||||
class SinkInParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x140, Unsafe.SizeOf<SinkInParameter>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter
|
||||
{
|
||||
class SinkOutStatusTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x20, Unsafe.SizeOf<SinkOutStatus>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Parameter
|
||||
{
|
||||
class SplitterInParamHeaderTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x20, Unsafe.SizeOf<SplitterInParameterHeader>());
|
||||
}
|
||||
}
|
||||
}
|
35
src/Ryujinx.Tests/Audio/Renderer/Server/AddressInfoTests.cs
Normal file
35
src/Ryujinx.Tests/Audio/Renderer/Server/AddressInfoTests.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
class AddressInfoTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x20, Unsafe.SizeOf<AddressInfo>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetReference()
|
||||
{
|
||||
MemoryPoolState[] memoryPoolState = new MemoryPoolState[1];
|
||||
memoryPoolState[0] = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu);
|
||||
memoryPoolState[0].SetCpuAddress(0x1000000, 0x10000);
|
||||
memoryPoolState[0].DspAddress = 0x4000000;
|
||||
|
||||
AddressInfo addressInfo = AddressInfo.Create(0x1000000, 0x1000);
|
||||
|
||||
addressInfo.ForceMappedDspAddress = 0x2000000;
|
||||
|
||||
Assert.AreEqual(0x2000000, addressInfo.GetReference(true));
|
||||
|
||||
addressInfo.SetupMemoryPool(memoryPoolState.AsSpan());
|
||||
|
||||
Assert.AreEqual(0x4000000, addressInfo.GetReference(true));
|
||||
}
|
||||
}
|
||||
}
|
296
src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs
Normal file
296
src/Ryujinx.Tests/Audio/Renderer/Server/BehaviourContextTests.cs
Normal file
|
@ -0,0 +1,296 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Server;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
public class BehaviourContextTests
|
||||
{
|
||||
[Test]
|
||||
public void TestCheckFeature()
|
||||
{
|
||||
int latestRevision = BehaviourContext.BaseRevisionMagic + BehaviourContext.LastRevision;
|
||||
int previousRevision = BehaviourContext.BaseRevisionMagic + (BehaviourContext.LastRevision - 1);
|
||||
int invalidRevision = BehaviourContext.BaseRevisionMagic + (BehaviourContext.LastRevision + 1);
|
||||
|
||||
Assert.IsTrue(BehaviourContext.CheckFeatureSupported(latestRevision, latestRevision));
|
||||
Assert.IsFalse(BehaviourContext.CheckFeatureSupported(previousRevision, latestRevision));
|
||||
Assert.IsTrue(BehaviourContext.CheckFeatureSupported(latestRevision, previousRevision));
|
||||
// In case we get an invalid revision, this is supposed to auto default to REV1 internally.. idk what the hell Nintendo was thinking here..
|
||||
Assert.IsTrue(BehaviourContext.CheckFeatureSupported(invalidRevision, latestRevision));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestsMemoryPoolForceMappingEnabled()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision1);
|
||||
|
||||
Assert.IsFalse(behaviourContext.IsMemoryPoolForceMappingEnabled());
|
||||
|
||||
behaviourContext.UpdateFlags(0x1);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsMemoryPoolForceMappingEnabled());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision1()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision1);
|
||||
|
||||
Assert.IsFalse(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsFalse(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsFalse(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsFalse(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsFalse(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsFalse(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(1, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision2()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision2);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsFalse(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsFalse(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsFalse(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsFalse(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsFalse(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(1, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision3()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision3);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsFalse(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsFalse(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsFalse(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsFalse(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.70f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(1, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision4()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision4);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsFalse(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsFalse(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsFalse(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.75f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(1, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(1, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision5()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision5);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision6()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision6);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsFalse(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision7()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision7);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsFalse(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(2, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision8()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision8);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision9()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision9);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsTrue(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsFalse(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(3, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRevision10()
|
||||
{
|
||||
BehaviourContext behaviourContext = new BehaviourContext();
|
||||
|
||||
behaviourContext.SetUserRevision(BehaviourContext.BaseRevisionMagic + BehaviourContext.Revision10);
|
||||
|
||||
Assert.IsTrue(behaviourContext.IsAdpcmLoopContextBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterSupported());
|
||||
Assert.IsTrue(behaviourContext.IsLongSizePreDelaySupported());
|
||||
Assert.IsTrue(behaviourContext.IsAudioUsbDeviceOutputSupported());
|
||||
Assert.IsTrue(behaviourContext.IsFlushVoiceWaveBuffersSupported());
|
||||
Assert.IsTrue(behaviourContext.IsSplitterBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsElapsedFrameCountSupported());
|
||||
Assert.IsTrue(behaviourContext.IsDecodingBehaviourFlagSupported());
|
||||
Assert.IsTrue(behaviourContext.IsBiquadFilterEffectStateClearBugFixed());
|
||||
Assert.IsTrue(behaviourContext.IsMixInParameterDirtyOnlyUpdateSupported());
|
||||
Assert.IsTrue(behaviourContext.IsWaveBufferVersion2Supported());
|
||||
Assert.IsTrue(behaviourContext.IsEffectInfoVersion2Supported());
|
||||
Assert.IsTrue(behaviourContext.IsBiquadFilterGroupedOptimizationSupported());
|
||||
|
||||
Assert.AreEqual(0.80f, behaviourContext.GetAudioRendererProcessingTimeLimit());
|
||||
Assert.AreEqual(4, behaviourContext.GetCommandProcessingTimeEstimatorVersion());
|
||||
Assert.AreEqual(2, behaviourContext.GetPerformanceMetricsDataFormat());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
class MemoryPoolStateTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(Unsafe.SizeOf<MemoryPoolState>(), 0x20);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContains()
|
||||
{
|
||||
MemoryPoolState memoryPool = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu);
|
||||
|
||||
memoryPool.SetCpuAddress(0x1000000, 0x1000);
|
||||
|
||||
memoryPool.DspAddress = 0x2000000;
|
||||
|
||||
Assert.IsTrue(memoryPool.Contains(0x1000000, 0x10));
|
||||
Assert.IsTrue(memoryPool.Contains(0x1000FE0, 0x10));
|
||||
Assert.IsTrue(memoryPool.Contains(0x1000FFF, 0x1));
|
||||
Assert.IsFalse(memoryPool.Contains(0x1000FFF, 0x2));
|
||||
Assert.IsFalse(memoryPool.Contains(0x1001000, 0x10));
|
||||
Assert.IsFalse(memoryPool.Contains(0x2000000, 0x10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTranslate()
|
||||
{
|
||||
MemoryPoolState memoryPool = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu);
|
||||
|
||||
memoryPool.SetCpuAddress(0x1000000, 0x1000);
|
||||
|
||||
memoryPool.DspAddress = 0x2000000;
|
||||
|
||||
Assert.AreEqual(0x2000FE0, memoryPool.Translate(0x1000FE0, 0x10));
|
||||
Assert.AreEqual(0x2000FFF, memoryPool.Translate(0x1000FFF, 0x1));
|
||||
Assert.AreEqual(0x0, memoryPool.Translate(0x1000FFF, 0x2));
|
||||
Assert.AreEqual(0x0, memoryPool.Translate(0x1001000, 0x10));
|
||||
Assert.AreEqual(0x0, memoryPool.Translate(0x2000000, 0x10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestIsMapped()
|
||||
{
|
||||
MemoryPoolState memoryPool = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu);
|
||||
|
||||
memoryPool.SetCpuAddress(0x1000000, 0x1000);
|
||||
|
||||
Assert.IsFalse(memoryPool.IsMapped());
|
||||
|
||||
memoryPool.DspAddress = 0x2000000;
|
||||
|
||||
Assert.IsTrue(memoryPool.IsMapped());
|
||||
}
|
||||
}
|
||||
}
|
15
src/Ryujinx.Tests/Audio/Renderer/Server/MixStateTests.cs
Normal file
15
src/Ryujinx.Tests/Audio/Renderer/Server/MixStateTests.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Server.Mix;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
class MixStateTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x940, Unsafe.SizeOf<MixState>());
|
||||
}
|
||||
}
|
||||
}
|
135
src/Ryujinx.Tests/Audio/Renderer/Server/PoolMapperTests.cs
Normal file
135
src/Ryujinx.Tests/Audio/Renderer/Server/PoolMapperTests.cs
Normal file
|
@ -0,0 +1,135 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio;
|
||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||
using System;
|
||||
using static Ryujinx.Audio.Renderer.Common.BehaviourParameter;
|
||||
using CpuAddress = System.UInt64;
|
||||
using DspAddress = System.UInt64;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
class PoolMapperTests
|
||||
{
|
||||
private const uint DummyProcessHandle = 0xCAFEBABE;
|
||||
|
||||
[Test]
|
||||
public void TestInitializeSystemPool()
|
||||
{
|
||||
PoolMapper poolMapper = new PoolMapper(DummyProcessHandle, true);
|
||||
MemoryPoolState memoryPoolDsp = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
|
||||
MemoryPoolState memoryPoolCpu = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu);
|
||||
|
||||
const CpuAddress CpuAddress = 0x20000;
|
||||
const DspAddress DspAddress = CpuAddress; // TODO: DSP LLE
|
||||
const ulong CpuSize = 0x1000;
|
||||
|
||||
Assert.IsFalse(poolMapper.InitializeSystemPool(ref memoryPoolCpu, CpuAddress, CpuSize));
|
||||
Assert.IsTrue(poolMapper.InitializeSystemPool(ref memoryPoolDsp, CpuAddress, CpuSize));
|
||||
|
||||
Assert.AreEqual(CpuAddress, memoryPoolDsp.CpuAddress);
|
||||
Assert.AreEqual(CpuSize, memoryPoolDsp.Size);
|
||||
Assert.AreEqual(DspAddress, memoryPoolDsp.DspAddress);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetProcessHandle()
|
||||
{
|
||||
PoolMapper poolMapper = new PoolMapper(DummyProcessHandle, true);
|
||||
MemoryPoolState memoryPoolDsp = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
|
||||
MemoryPoolState memoryPoolCpu = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu);
|
||||
|
||||
Assert.AreEqual(0xFFFF8001, poolMapper.GetProcessHandle(ref memoryPoolCpu));
|
||||
Assert.AreEqual(DummyProcessHandle, poolMapper.GetProcessHandle(ref memoryPoolDsp));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMappings()
|
||||
{
|
||||
PoolMapper poolMapper = new PoolMapper(DummyProcessHandle, true);
|
||||
MemoryPoolState memoryPoolDsp = MemoryPoolState.Create(MemoryPoolState.LocationType.Dsp);
|
||||
MemoryPoolState memoryPoolCpu = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu);
|
||||
|
||||
const CpuAddress CpuAddress = 0x20000;
|
||||
const DspAddress DspAddress = CpuAddress; // TODO: DSP LLE
|
||||
const ulong CpuSize = 0x1000;
|
||||
|
||||
memoryPoolDsp.SetCpuAddress(CpuAddress, CpuSize);
|
||||
memoryPoolCpu.SetCpuAddress(CpuAddress, CpuSize);
|
||||
|
||||
Assert.AreEqual(DspAddress, poolMapper.Map(ref memoryPoolCpu));
|
||||
Assert.AreEqual(DspAddress, poolMapper.Map(ref memoryPoolDsp));
|
||||
Assert.AreEqual(DspAddress, memoryPoolDsp.DspAddress);
|
||||
Assert.IsTrue(poolMapper.Unmap(ref memoryPoolCpu));
|
||||
|
||||
memoryPoolDsp.IsUsed = true;
|
||||
Assert.IsFalse(poolMapper.Unmap(ref memoryPoolDsp));
|
||||
memoryPoolDsp.IsUsed = false;
|
||||
Assert.IsTrue(poolMapper.Unmap(ref memoryPoolDsp));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTryAttachBuffer()
|
||||
{
|
||||
const CpuAddress CpuAddress = 0x20000;
|
||||
const DspAddress DspAddress = CpuAddress; // TODO: DSP LLE
|
||||
const ulong CpuSize = 0x1000;
|
||||
|
||||
const int MemoryPoolStateArraySize = 0x10;
|
||||
const CpuAddress CpuAddressRegionEnding = CpuAddress * MemoryPoolStateArraySize;
|
||||
|
||||
MemoryPoolState[] memoryPoolStateArray = new MemoryPoolState[MemoryPoolStateArraySize];
|
||||
|
||||
for (int i = 0; i < memoryPoolStateArray.Length; i++)
|
||||
{
|
||||
memoryPoolStateArray[i] = MemoryPoolState.Create(MemoryPoolState.LocationType.Cpu);
|
||||
memoryPoolStateArray[i].SetCpuAddress(CpuAddress + (ulong)i * CpuSize, CpuSize);
|
||||
}
|
||||
|
||||
ErrorInfo errorInfo;
|
||||
|
||||
AddressInfo addressInfo = AddressInfo.Create();
|
||||
|
||||
PoolMapper poolMapper = new PoolMapper(DummyProcessHandle, true);
|
||||
|
||||
Assert.IsTrue(poolMapper.TryAttachBuffer(out errorInfo, ref addressInfo, 0, 0));
|
||||
|
||||
Assert.AreEqual(ResultCode.InvalidAddressInfo, errorInfo.ErrorCode);
|
||||
Assert.AreEqual(0, errorInfo.ExtraErrorInfo);
|
||||
Assert.AreEqual(0, addressInfo.ForceMappedDspAddress);
|
||||
|
||||
Assert.IsTrue(poolMapper.TryAttachBuffer(out errorInfo, ref addressInfo, CpuAddress, CpuSize));
|
||||
|
||||
Assert.AreEqual(ResultCode.InvalidAddressInfo, errorInfo.ErrorCode);
|
||||
Assert.AreEqual(CpuAddress, errorInfo.ExtraErrorInfo);
|
||||
Assert.AreEqual(DspAddress, addressInfo.ForceMappedDspAddress);
|
||||
|
||||
poolMapper = new PoolMapper(DummyProcessHandle, false);
|
||||
|
||||
Assert.IsFalse(poolMapper.TryAttachBuffer(out errorInfo, ref addressInfo, 0, 0));
|
||||
|
||||
addressInfo.ForceMappedDspAddress = 0;
|
||||
|
||||
Assert.IsFalse(poolMapper.TryAttachBuffer(out errorInfo, ref addressInfo, CpuAddress, CpuSize));
|
||||
|
||||
Assert.AreEqual(ResultCode.InvalidAddressInfo, errorInfo.ErrorCode);
|
||||
Assert.AreEqual(CpuAddress, errorInfo.ExtraErrorInfo);
|
||||
Assert.AreEqual(0, addressInfo.ForceMappedDspAddress);
|
||||
|
||||
poolMapper = new PoolMapper(DummyProcessHandle, memoryPoolStateArray.AsMemory(), false);
|
||||
|
||||
Assert.IsFalse(poolMapper.TryAttachBuffer(out errorInfo, ref addressInfo, CpuAddressRegionEnding, CpuSize));
|
||||
|
||||
Assert.AreEqual(ResultCode.InvalidAddressInfo, errorInfo.ErrorCode);
|
||||
Assert.AreEqual(CpuAddressRegionEnding, errorInfo.ExtraErrorInfo);
|
||||
Assert.AreEqual(0, addressInfo.ForceMappedDspAddress);
|
||||
Assert.IsFalse(addressInfo.HasMemoryPoolState);
|
||||
|
||||
Assert.IsTrue(poolMapper.TryAttachBuffer(out errorInfo, ref addressInfo, CpuAddress, CpuSize));
|
||||
|
||||
Assert.AreEqual(ResultCode.Success, errorInfo.ErrorCode);
|
||||
Assert.AreEqual(0, errorInfo.ExtraErrorInfo);
|
||||
Assert.AreEqual(0, addressInfo.ForceMappedDspAddress);
|
||||
Assert.IsTrue(addressInfo.HasMemoryPoolState);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Server.Splitter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
class SplitterDestinationTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0xE0, Unsafe.SizeOf<SplitterDestination>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Server.Splitter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
class SplitterStateTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x20, Unsafe.SizeOf<SplitterState>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Server.Voice;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
class VoiceChannelResourceTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0xD0, Unsafe.SizeOf<VoiceChannelResource>());
|
||||
}
|
||||
}
|
||||
}
|
15
src/Ryujinx.Tests/Audio/Renderer/Server/VoiceStateTests.cs
Normal file
15
src/Ryujinx.Tests/Audio/Renderer/Server/VoiceStateTests.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Server.Voice;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
class VoiceStateTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.LessOrEqual(Unsafe.SizeOf<VoiceState>(), 0x220);
|
||||
}
|
||||
}
|
||||
}
|
15
src/Ryujinx.Tests/Audio/Renderer/Server/WaveBufferTests.cs
Normal file
15
src/Ryujinx.Tests/Audio/Renderer/Server/WaveBufferTests.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Server.Voice;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer.Server
|
||||
{
|
||||
class WaveBufferTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x58, Unsafe.SizeOf<WaveBuffer>());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer
|
||||
{
|
||||
class VoiceChannelResourceInParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x70, Unsafe.SizeOf<VoiceChannelResourceInParameter>());
|
||||
}
|
||||
}
|
||||
}
|
15
src/Ryujinx.Tests/Audio/Renderer/VoiceInParameterTests.cs
Normal file
15
src/Ryujinx.Tests/Audio/Renderer/VoiceInParameterTests.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer
|
||||
{
|
||||
class VoiceInParameterTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x170, Unsafe.SizeOf<VoiceInParameter>());
|
||||
}
|
||||
}
|
||||
}
|
15
src/Ryujinx.Tests/Audio/Renderer/VoiceOutStatusTests.cs
Normal file
15
src/Ryujinx.Tests/Audio/Renderer/VoiceOutStatusTests.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Tests.Audio.Renderer
|
||||
{
|
||||
class VoiceOutStatusTests
|
||||
{
|
||||
[Test]
|
||||
public void EnsureTypeSize()
|
||||
{
|
||||
Assert.AreEqual(0x10, Unsafe.SizeOf<VoiceOutStatus>());
|
||||
}
|
||||
}
|
||||
}
|
46
src/Ryujinx.Tests/Cpu/Arm64CodeGenCommonTests.cs
Normal file
46
src/Ryujinx.Tests/Cpu/Arm64CodeGenCommonTests.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using ARMeilleure.CodeGen.Arm64;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
public class Arm64CodeGenCommonTests
|
||||
{
|
||||
public struct TestCase
|
||||
{
|
||||
public ulong Value;
|
||||
public bool Valid;
|
||||
public int ImmN;
|
||||
public int ImmS;
|
||||
public int ImmR;
|
||||
}
|
||||
|
||||
public static readonly TestCase[] TestCases =
|
||||
{
|
||||
new() { Value = 0, Valid = false, ImmN = 0, ImmS = 0, ImmR = 0 },
|
||||
new() { Value = 0x970977f35f848714, Valid = false, ImmN = 0, ImmS = 0, ImmR = 0 },
|
||||
new() { Value = 0xffffffffffffffff, Valid = false, ImmN = 0, ImmS = 0, ImmR = 0 },
|
||||
new() { Value = 0x5555555555555555, Valid = true, ImmN = 0, ImmS = 0x3c, ImmR = 0 },
|
||||
new() { Value = 0xaaaaaaaaaaaaaaaa, Valid = true, ImmN = 0, ImmS = 0x3c, ImmR = 1 },
|
||||
new() { Value = 0x6666666666666666, Valid = true, ImmN = 0, ImmS = 0x39, ImmR = 3 },
|
||||
new() { Value = 0x1c1c1c1c1c1c1c1c, Valid = true, ImmN = 0, ImmS = 0x32, ImmR = 6 },
|
||||
new() { Value = 0x0f0f0f0f0f0f0f0f, Valid = true, ImmN = 0, ImmS = 0x33, ImmR = 0 },
|
||||
new() { Value = 0xf1f1f1f1f1f1f1f1, Valid = true, ImmN = 0, ImmS = 0x34, ImmR = 4 },
|
||||
new() { Value = 0xe7e7e7e7e7e7e7e7, Valid = true, ImmN = 0, ImmS = 0x35, ImmR = 3 },
|
||||
new() { Value = 0xc001c001c001c001, Valid = true, ImmN = 0, ImmS = 0x22, ImmR = 2 },
|
||||
new() { Value = 0x0000038000000380, Valid = true, ImmN = 0, ImmS = 0x02, ImmR = 25 },
|
||||
new() { Value = 0xffff8fffffff8fff, Valid = true, ImmN = 0, ImmS = 0x1c, ImmR = 17 },
|
||||
new() { Value = 0x000000000ffff800, Valid = true, ImmN = 1, ImmS = 0x10, ImmR = 53 },
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void BitImmTests([ValueSource(nameof(TestCases))] TestCase test)
|
||||
{
|
||||
bool valid = CodeGenCommon.TryEncodeBitMask(test.Value, out int immN, out int immS, out int immR);
|
||||
|
||||
Assert.That(valid, Is.EqualTo(test.Valid));
|
||||
Assert.That(immN, Is.EqualTo(test.ImmN));
|
||||
Assert.That(immS, Is.EqualTo(test.ImmS));
|
||||
Assert.That(immR, Is.EqualTo(test.ImmR));
|
||||
}
|
||||
}
|
||||
}
|
39
src/Ryujinx.Tests/Cpu/CpuContext.cs
Normal file
39
src/Ryujinx.Tests/Cpu/CpuContext.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
public class CpuContext
|
||||
{
|
||||
private readonly Translator _translator;
|
||||
|
||||
public CpuContext(IMemoryManager memory, bool for64Bit)
|
||||
{
|
||||
_translator = new Translator(new JitMemoryAllocator(), memory, for64Bit);
|
||||
memory.UnmapEvent += UnmapHandler;
|
||||
}
|
||||
|
||||
private void UnmapHandler(ulong address, ulong size)
|
||||
{
|
||||
_translator.InvalidateJitCacheRegion(address, size);
|
||||
}
|
||||
|
||||
public static ExecutionContext CreateExecutionContext()
|
||||
{
|
||||
return new ExecutionContext(new JitMemoryAllocator(), new TickSource(19200000));
|
||||
}
|
||||
|
||||
public void Execute(ExecutionContext context, ulong address)
|
||||
{
|
||||
_translator.Execute(context, address);
|
||||
}
|
||||
|
||||
public void InvalidateCacheRegion(ulong address, ulong size)
|
||||
{
|
||||
_translator.InvalidateJitCacheRegion(address, size);
|
||||
}
|
||||
}
|
||||
}
|
578
src/Ryujinx.Tests/Cpu/CpuTest.cs
Normal file
578
src/Ryujinx.Tests/Cpu/CpuTest.cs
Normal file
|
@ -0,0 +1,578 @@
|
|||
using ARMeilleure;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using NUnit.Framework;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.Tests.Unicorn;
|
||||
using System;
|
||||
using MemoryPermission = Ryujinx.Tests.Unicorn.MemoryPermission;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[TestFixture]
|
||||
public class CpuTest
|
||||
{
|
||||
protected const ulong Size = 0x1000;
|
||||
protected const ulong CodeBaseAddress = 0x1000;
|
||||
protected const ulong DataBaseAddress = CodeBaseAddress + Size;
|
||||
|
||||
private static bool Ignore_FpcrFz = false;
|
||||
private static bool Ignore_FpcrDn = false;
|
||||
|
||||
private static bool IgnoreAllExcept_FpsrQc = false;
|
||||
|
||||
private ulong _currAddress;
|
||||
|
||||
private MemoryBlock _ram;
|
||||
|
||||
private MemoryManager _memory;
|
||||
|
||||
private ExecutionContext _context;
|
||||
|
||||
private CpuContext _cpuContext;
|
||||
|
||||
private UnicornAArch64 _unicornEmu;
|
||||
|
||||
private bool _usingMemory;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_currAddress = CodeBaseAddress;
|
||||
|
||||
_ram = new MemoryBlock(Size * 2);
|
||||
_memory = new MemoryManager(_ram, 1ul << 16);
|
||||
_memory.IncrementReferenceCount();
|
||||
_memory.Map(CodeBaseAddress, 0, Size * 2, MemoryMapFlags.Private);
|
||||
|
||||
_context = CpuContext.CreateExecutionContext();
|
||||
Translator.IsReadyForTranslation.Set();
|
||||
|
||||
_cpuContext = new CpuContext(_memory, for64Bit: true);
|
||||
|
||||
// Prevent registering LCQ functions in the FunctionTable to avoid initializing and populating the table,
|
||||
// which improves test durations.
|
||||
Optimizations.AllowLcqInFunctionTable = false;
|
||||
Optimizations.UseUnmanagedDispatchLoop = false;
|
||||
|
||||
_unicornEmu = new UnicornAArch64();
|
||||
_unicornEmu.MemoryMap(CodeBaseAddress, Size, MemoryPermission.Read | MemoryPermission.Exec);
|
||||
_unicornEmu.MemoryMap(DataBaseAddress, Size, MemoryPermission.Read | MemoryPermission.Write);
|
||||
_unicornEmu.PC = CodeBaseAddress;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
|
||||
_memory.DecrementReferenceCount();
|
||||
_context.Dispose();
|
||||
_ram.Dispose();
|
||||
|
||||
_memory = null;
|
||||
_context = null;
|
||||
_cpuContext = null;
|
||||
_unicornEmu = null;
|
||||
|
||||
_usingMemory = false;
|
||||
}
|
||||
|
||||
protected void Reset()
|
||||
{
|
||||
Teardown();
|
||||
Setup();
|
||||
}
|
||||
|
||||
protected void Opcode(uint opcode)
|
||||
{
|
||||
_memory.Write(_currAddress, opcode);
|
||||
|
||||
_unicornEmu.MemoryWrite32(_currAddress, opcode);
|
||||
|
||||
_currAddress += 4;
|
||||
}
|
||||
|
||||
protected ExecutionContext GetContext() => _context;
|
||||
|
||||
protected void SetContext(ulong x0 = 0,
|
||||
ulong x1 = 0,
|
||||
ulong x2 = 0,
|
||||
ulong x3 = 0,
|
||||
ulong x31 = 0,
|
||||
V128 v0 = default,
|
||||
V128 v1 = default,
|
||||
V128 v2 = default,
|
||||
V128 v3 = default,
|
||||
V128 v4 = default,
|
||||
V128 v5 = default,
|
||||
V128 v30 = default,
|
||||
V128 v31 = default,
|
||||
bool overflow = false,
|
||||
bool carry = false,
|
||||
bool zero = false,
|
||||
bool negative = false,
|
||||
int fpcr = 0,
|
||||
int fpsr = 0)
|
||||
{
|
||||
_context.SetX(0, x0);
|
||||
_context.SetX(1, x1);
|
||||
_context.SetX(2, x2);
|
||||
_context.SetX(3, x3);
|
||||
_context.SetX(31, x31);
|
||||
|
||||
_context.SetV(0, v0);
|
||||
_context.SetV(1, v1);
|
||||
_context.SetV(2, v2);
|
||||
_context.SetV(3, v3);
|
||||
_context.SetV(4, v4);
|
||||
_context.SetV(5, v5);
|
||||
_context.SetV(30, v30);
|
||||
_context.SetV(31, v31);
|
||||
|
||||
_context.SetPstateFlag(PState.VFlag, overflow);
|
||||
_context.SetPstateFlag(PState.CFlag, carry);
|
||||
_context.SetPstateFlag(PState.ZFlag, zero);
|
||||
_context.SetPstateFlag(PState.NFlag, negative);
|
||||
|
||||
_context.Fpcr = (FPCR)fpcr;
|
||||
_context.Fpsr = (FPSR)fpsr;
|
||||
|
||||
_unicornEmu.X[0] = x0;
|
||||
_unicornEmu.X[1] = x1;
|
||||
_unicornEmu.X[2] = x2;
|
||||
_unicornEmu.X[3] = x3;
|
||||
_unicornEmu.SP = x31;
|
||||
|
||||
_unicornEmu.Q[0] = V128ToSimdValue(v0);
|
||||
_unicornEmu.Q[1] = V128ToSimdValue(v1);
|
||||
_unicornEmu.Q[2] = V128ToSimdValue(v2);
|
||||
_unicornEmu.Q[3] = V128ToSimdValue(v3);
|
||||
_unicornEmu.Q[4] = V128ToSimdValue(v4);
|
||||
_unicornEmu.Q[5] = V128ToSimdValue(v5);
|
||||
_unicornEmu.Q[30] = V128ToSimdValue(v30);
|
||||
_unicornEmu.Q[31] = V128ToSimdValue(v31);
|
||||
|
||||
_unicornEmu.OverflowFlag = overflow;
|
||||
_unicornEmu.CarryFlag = carry;
|
||||
_unicornEmu.ZeroFlag = zero;
|
||||
_unicornEmu.NegativeFlag = negative;
|
||||
|
||||
_unicornEmu.Fpcr = fpcr;
|
||||
_unicornEmu.Fpsr = fpsr;
|
||||
}
|
||||
|
||||
protected void ExecuteOpcodes(bool runUnicorn = true)
|
||||
{
|
||||
_cpuContext.Execute(_context, CodeBaseAddress);
|
||||
|
||||
if (runUnicorn)
|
||||
{
|
||||
_unicornEmu.RunForCount((_currAddress - CodeBaseAddress - 4) / 4);
|
||||
}
|
||||
}
|
||||
|
||||
protected ExecutionContext SingleOpcode(uint opcode,
|
||||
ulong x0 = 0,
|
||||
ulong x1 = 0,
|
||||
ulong x2 = 0,
|
||||
ulong x3 = 0,
|
||||
ulong x31 = 0,
|
||||
V128 v0 = default,
|
||||
V128 v1 = default,
|
||||
V128 v2 = default,
|
||||
V128 v3 = default,
|
||||
V128 v4 = default,
|
||||
V128 v5 = default,
|
||||
V128 v30 = default,
|
||||
V128 v31 = default,
|
||||
bool overflow = false,
|
||||
bool carry = false,
|
||||
bool zero = false,
|
||||
bool negative = false,
|
||||
int fpcr = 0,
|
||||
int fpsr = 0,
|
||||
bool runUnicorn = true)
|
||||
{
|
||||
if (Ignore_FpcrFz)
|
||||
{
|
||||
fpcr &= ~(1 << (int)Fpcr.Fz);
|
||||
}
|
||||
|
||||
if (Ignore_FpcrDn)
|
||||
{
|
||||
fpcr &= ~(1 << (int)Fpcr.Dn);
|
||||
}
|
||||
|
||||
Opcode(opcode);
|
||||
Opcode(0xD65F03C0); // RET
|
||||
SetContext(x0, x1, x2, x3, x31, v0, v1, v2, v3, v4, v5, v30, v31, overflow, carry, zero, negative, fpcr, fpsr);
|
||||
ExecuteOpcodes(runUnicorn);
|
||||
|
||||
return GetContext();
|
||||
}
|
||||
|
||||
protected void SetWorkingMemory(ulong offset, byte[] data)
|
||||
{
|
||||
_memory.Write(DataBaseAddress + offset, data);
|
||||
|
||||
_unicornEmu.MemoryWrite(DataBaseAddress + offset, data);
|
||||
|
||||
_usingMemory = true; // When true, CompareAgainstUnicorn checks the working memory for equality too.
|
||||
}
|
||||
|
||||
protected void SetWorkingMemory(ulong offset, byte data)
|
||||
{
|
||||
_memory.Write(DataBaseAddress + offset, data);
|
||||
|
||||
_unicornEmu.MemoryWrite8(DataBaseAddress + offset, data);
|
||||
|
||||
_usingMemory = true; // When true, CompareAgainstUnicorn checks the working memory for equality too.
|
||||
}
|
||||
|
||||
/// <summary>Rounding Mode control field.</summary>
|
||||
public enum RMode
|
||||
{
|
||||
/// <summary>Round to Nearest mode.</summary>
|
||||
Rn,
|
||||
/// <summary>Round towards Plus Infinity mode.</summary>
|
||||
Rp,
|
||||
/// <summary>Round towards Minus Infinity mode.</summary>
|
||||
Rm,
|
||||
/// <summary>Round towards Zero mode.</summary>
|
||||
Rz
|
||||
};
|
||||
|
||||
/// <summary>Floating-point Control Register.</summary>
|
||||
protected enum Fpcr
|
||||
{
|
||||
/// <summary>Rounding Mode control field.</summary>
|
||||
RMode = 22,
|
||||
/// <summary>Flush-to-zero mode control bit.</summary>
|
||||
Fz = 24,
|
||||
/// <summary>Default NaN mode control bit.</summary>
|
||||
Dn = 25,
|
||||
/// <summary>Alternative half-precision control bit.</summary>
|
||||
Ahp = 26
|
||||
}
|
||||
|
||||
/// <summary>Floating-point Status Register.</summary>
|
||||
[Flags] protected enum Fpsr
|
||||
{
|
||||
None = 0,
|
||||
|
||||
/// <summary>Invalid Operation cumulative floating-point exception bit.</summary>
|
||||
Ioc = 1 << 0,
|
||||
/// <summary>Divide by Zero cumulative floating-point exception bit.</summary>
|
||||
Dzc = 1 << 1,
|
||||
/// <summary>Overflow cumulative floating-point exception bit.</summary>
|
||||
Ofc = 1 << 2,
|
||||
/// <summary>Underflow cumulative floating-point exception bit.</summary>
|
||||
Ufc = 1 << 3,
|
||||
/// <summary>Inexact cumulative floating-point exception bit.</summary>
|
||||
Ixc = 1 << 4,
|
||||
/// <summary>Input Denormal cumulative floating-point exception bit.</summary>
|
||||
Idc = 1 << 7,
|
||||
|
||||
/// <summary>Cumulative saturation bit.</summary>
|
||||
Qc = 1 << 27
|
||||
}
|
||||
|
||||
[Flags] protected enum FpSkips
|
||||
{
|
||||
None = 0,
|
||||
|
||||
IfNaNS = 1,
|
||||
IfNaND = 2,
|
||||
|
||||
IfUnderflow = 4,
|
||||
IfOverflow = 8
|
||||
}
|
||||
|
||||
protected enum FpTolerances
|
||||
{
|
||||
None,
|
||||
|
||||
UpToOneUlpsS,
|
||||
UpToOneUlpsD
|
||||
}
|
||||
|
||||
protected void CompareAgainstUnicorn(
|
||||
Fpsr fpsrMask = Fpsr.None,
|
||||
FpSkips fpSkips = FpSkips.None,
|
||||
FpTolerances fpTolerances = FpTolerances.None)
|
||||
{
|
||||
if (IgnoreAllExcept_FpsrQc)
|
||||
{
|
||||
fpsrMask &= Fpsr.Qc;
|
||||
}
|
||||
|
||||
if (fpSkips != FpSkips.None)
|
||||
{
|
||||
ManageFpSkips(fpSkips);
|
||||
}
|
||||
|
||||
Assert.That(_context.GetX(0), Is.EqualTo(_unicornEmu.X[0]), "X0");
|
||||
Assert.That(_context.GetX(1), Is.EqualTo(_unicornEmu.X[1]), "X1");
|
||||
Assert.That(_context.GetX(2), Is.EqualTo(_unicornEmu.X[2]), "X2");
|
||||
Assert.That(_context.GetX(3), Is.EqualTo(_unicornEmu.X[3]), "X3");
|
||||
Assert.That(_context.GetX(4), Is.EqualTo(_unicornEmu.X[4]));
|
||||
Assert.That(_context.GetX(5), Is.EqualTo(_unicornEmu.X[5]));
|
||||
Assert.That(_context.GetX(6), Is.EqualTo(_unicornEmu.X[6]));
|
||||
Assert.That(_context.GetX(7), Is.EqualTo(_unicornEmu.X[7]));
|
||||
Assert.That(_context.GetX(8), Is.EqualTo(_unicornEmu.X[8]));
|
||||
Assert.That(_context.GetX(9), Is.EqualTo(_unicornEmu.X[9]));
|
||||
Assert.That(_context.GetX(10), Is.EqualTo(_unicornEmu.X[10]));
|
||||
Assert.That(_context.GetX(11), Is.EqualTo(_unicornEmu.X[11]));
|
||||
Assert.That(_context.GetX(12), Is.EqualTo(_unicornEmu.X[12]));
|
||||
Assert.That(_context.GetX(13), Is.EqualTo(_unicornEmu.X[13]));
|
||||
Assert.That(_context.GetX(14), Is.EqualTo(_unicornEmu.X[14]));
|
||||
Assert.That(_context.GetX(15), Is.EqualTo(_unicornEmu.X[15]));
|
||||
Assert.That(_context.GetX(16), Is.EqualTo(_unicornEmu.X[16]));
|
||||
Assert.That(_context.GetX(17), Is.EqualTo(_unicornEmu.X[17]));
|
||||
Assert.That(_context.GetX(18), Is.EqualTo(_unicornEmu.X[18]));
|
||||
Assert.That(_context.GetX(19), Is.EqualTo(_unicornEmu.X[19]));
|
||||
Assert.That(_context.GetX(20), Is.EqualTo(_unicornEmu.X[20]));
|
||||
Assert.That(_context.GetX(21), Is.EqualTo(_unicornEmu.X[21]));
|
||||
Assert.That(_context.GetX(22), Is.EqualTo(_unicornEmu.X[22]));
|
||||
Assert.That(_context.GetX(23), Is.EqualTo(_unicornEmu.X[23]));
|
||||
Assert.That(_context.GetX(24), Is.EqualTo(_unicornEmu.X[24]));
|
||||
Assert.That(_context.GetX(25), Is.EqualTo(_unicornEmu.X[25]));
|
||||
Assert.That(_context.GetX(26), Is.EqualTo(_unicornEmu.X[26]));
|
||||
Assert.That(_context.GetX(27), Is.EqualTo(_unicornEmu.X[27]));
|
||||
Assert.That(_context.GetX(28), Is.EqualTo(_unicornEmu.X[28]));
|
||||
Assert.That(_context.GetX(29), Is.EqualTo(_unicornEmu.X[29]));
|
||||
Assert.That(_context.GetX(30), Is.EqualTo(_unicornEmu.X[30]));
|
||||
Assert.That(_context.GetX(31), Is.EqualTo(_unicornEmu.SP), "X31");
|
||||
|
||||
if (fpTolerances == FpTolerances.None)
|
||||
{
|
||||
Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0]), "V0");
|
||||
}
|
||||
else
|
||||
{
|
||||
ManageFpTolerances(fpTolerances);
|
||||
}
|
||||
Assert.That(V128ToSimdValue(_context.GetV(1)), Is.EqualTo(_unicornEmu.Q[1]), "V1");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(2)), Is.EqualTo(_unicornEmu.Q[2]), "V2");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(3)), Is.EqualTo(_unicornEmu.Q[3]), "V3");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(4)), Is.EqualTo(_unicornEmu.Q[4]), "V4");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(5)), Is.EqualTo(_unicornEmu.Q[5]), "V5");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(6)), Is.EqualTo(_unicornEmu.Q[6]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(7)), Is.EqualTo(_unicornEmu.Q[7]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(8)), Is.EqualTo(_unicornEmu.Q[8]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(9)), Is.EqualTo(_unicornEmu.Q[9]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(10)), Is.EqualTo(_unicornEmu.Q[10]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(11)), Is.EqualTo(_unicornEmu.Q[11]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(12)), Is.EqualTo(_unicornEmu.Q[12]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(13)), Is.EqualTo(_unicornEmu.Q[13]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(14)), Is.EqualTo(_unicornEmu.Q[14]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(15)), Is.EqualTo(_unicornEmu.Q[15]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(16)), Is.EqualTo(_unicornEmu.Q[16]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(17)), Is.EqualTo(_unicornEmu.Q[17]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(18)), Is.EqualTo(_unicornEmu.Q[18]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(19)), Is.EqualTo(_unicornEmu.Q[19]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(20)), Is.EqualTo(_unicornEmu.Q[20]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(21)), Is.EqualTo(_unicornEmu.Q[21]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(22)), Is.EqualTo(_unicornEmu.Q[22]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(23)), Is.EqualTo(_unicornEmu.Q[23]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(24)), Is.EqualTo(_unicornEmu.Q[24]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(25)), Is.EqualTo(_unicornEmu.Q[25]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(26)), Is.EqualTo(_unicornEmu.Q[26]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(27)), Is.EqualTo(_unicornEmu.Q[27]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(28)), Is.EqualTo(_unicornEmu.Q[28]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(29)), Is.EqualTo(_unicornEmu.Q[29]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(30)), Is.EqualTo(_unicornEmu.Q[30]), "V30");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(31)), Is.EqualTo(_unicornEmu.Q[31]), "V31");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(_context.GetPstateFlag(PState.VFlag), Is.EqualTo(_unicornEmu.OverflowFlag), "VFlag");
|
||||
Assert.That(_context.GetPstateFlag(PState.CFlag), Is.EqualTo(_unicornEmu.CarryFlag), "CFlag");
|
||||
Assert.That(_context.GetPstateFlag(PState.ZFlag), Is.EqualTo(_unicornEmu.ZeroFlag), "ZFlag");
|
||||
Assert.That(_context.GetPstateFlag(PState.NFlag), Is.EqualTo(_unicornEmu.NegativeFlag), "NFlag");
|
||||
});
|
||||
|
||||
Assert.That((int)_context.Fpcr, Is.EqualTo(_unicornEmu.Fpcr), "Fpcr");
|
||||
Assert.That((int)_context.Fpsr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpsr & (int)fpsrMask), "Fpsr");
|
||||
|
||||
if (_usingMemory)
|
||||
{
|
||||
byte[] mem = _memory.GetSpan(DataBaseAddress, (int)Size).ToArray();
|
||||
byte[] unicornMem = _unicornEmu.MemoryRead(DataBaseAddress, Size);
|
||||
|
||||
Assert.That(mem, Is.EqualTo(unicornMem), "Data");
|
||||
}
|
||||
}
|
||||
|
||||
private void ManageFpSkips(FpSkips fpSkips)
|
||||
{
|
||||
if (fpSkips.HasFlag(FpSkips.IfNaNS))
|
||||
{
|
||||
if (float.IsNaN(_unicornEmu.Q[0].AsFloat()))
|
||||
{
|
||||
Assert.Ignore("NaN test.");
|
||||
}
|
||||
}
|
||||
else if (fpSkips.HasFlag(FpSkips.IfNaND))
|
||||
{
|
||||
if (double.IsNaN(_unicornEmu.Q[0].AsDouble()))
|
||||
{
|
||||
Assert.Ignore("NaN test.");
|
||||
}
|
||||
}
|
||||
|
||||
if (fpSkips.HasFlag(FpSkips.IfUnderflow))
|
||||
{
|
||||
if ((_unicornEmu.Fpsr & (int)Fpsr.Ufc) != 0)
|
||||
{
|
||||
Assert.Ignore("Underflow test.");
|
||||
}
|
||||
}
|
||||
|
||||
if (fpSkips.HasFlag(FpSkips.IfOverflow))
|
||||
{
|
||||
if ((_unicornEmu.Fpsr & (int)Fpsr.Ofc) != 0)
|
||||
{
|
||||
Assert.Ignore("Overflow test.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ManageFpTolerances(FpTolerances fpTolerances)
|
||||
{
|
||||
bool IsNormalOrSubnormalS(float f) => float.IsNormal(f) || float.IsSubnormal(f);
|
||||
bool IsNormalOrSubnormalD(double d) => double.IsNormal(d) || double.IsSubnormal(d);
|
||||
|
||||
if (!Is.EqualTo(_unicornEmu.Q[0]).ApplyTo(V128ToSimdValue(_context.GetV(0))).IsSuccess)
|
||||
{
|
||||
if (fpTolerances == FpTolerances.UpToOneUlpsS)
|
||||
{
|
||||
if (IsNormalOrSubnormalS(_unicornEmu.Q[0].AsFloat()) &&
|
||||
IsNormalOrSubnormalS(_context.GetV(0).As<float>()))
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That (_context.GetV(0).Extract<float>(0),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetFloat(0)).Within(1).Ulps, "V0[0]");
|
||||
Assert.That (_context.GetV(0).Extract<float>(1),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetFloat(1)).Within(1).Ulps, "V0[1]");
|
||||
Assert.That (_context.GetV(0).Extract<float>(2),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetFloat(2)).Within(1).Ulps, "V0[2]");
|
||||
Assert.That (_context.GetV(0).Extract<float>(3),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetFloat(3)).Within(1).Ulps, "V0[3]");
|
||||
});
|
||||
|
||||
Console.WriteLine(fpTolerances);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0]));
|
||||
}
|
||||
}
|
||||
|
||||
if (fpTolerances == FpTolerances.UpToOneUlpsD)
|
||||
{
|
||||
if (IsNormalOrSubnormalD(_unicornEmu.Q[0].AsDouble()) &&
|
||||
IsNormalOrSubnormalD(_context.GetV(0).As<double>()))
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That (_context.GetV(0).Extract<double>(0),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetDouble(0)).Within(1).Ulps, "V0[0]");
|
||||
Assert.That (_context.GetV(0).Extract<double>(1),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetDouble(1)).Within(1).Ulps, "V0[1]");
|
||||
});
|
||||
|
||||
Console.WriteLine(fpTolerances);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SimdValue V128ToSimdValue(V128 value)
|
||||
{
|
||||
return new SimdValue(value.Extract<ulong>(0), value.Extract<ulong>(1));
|
||||
}
|
||||
|
||||
protected static V128 MakeVectorScalar(float value) => new V128(value);
|
||||
protected static V128 MakeVectorScalar(double value) => new V128(value);
|
||||
|
||||
protected static V128 MakeVectorE0(ulong e0) => new V128(e0, 0);
|
||||
protected static V128 MakeVectorE1(ulong e1) => new V128(0, e1);
|
||||
|
||||
protected static V128 MakeVectorE0E1(ulong e0, ulong e1) => new V128(e0, e1);
|
||||
|
||||
protected static ulong GetVectorE0(V128 vector) => vector.Extract<ulong>(0);
|
||||
protected static ulong GetVectorE1(V128 vector) => vector.Extract<ulong>(1);
|
||||
|
||||
protected static ushort GenNormalH()
|
||||
{
|
||||
uint rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextUShort();
|
||||
while (( rnd & 0x7C00u) == 0u ||
|
||||
(~rnd & 0x7C00u) == 0u);
|
||||
|
||||
return (ushort)rnd;
|
||||
}
|
||||
|
||||
protected static ushort GenSubnormalH()
|
||||
{
|
||||
uint rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextUShort();
|
||||
while ((rnd & 0x03FFu) == 0u);
|
||||
|
||||
return (ushort)(rnd & 0x83FFu);
|
||||
}
|
||||
|
||||
protected static uint GenNormalS()
|
||||
{
|
||||
uint rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextUInt();
|
||||
while (( rnd & 0x7F800000u) == 0u ||
|
||||
(~rnd & 0x7F800000u) == 0u);
|
||||
|
||||
return rnd;
|
||||
}
|
||||
|
||||
protected static uint GenSubnormalS()
|
||||
{
|
||||
uint rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextUInt();
|
||||
while ((rnd & 0x007FFFFFu) == 0u);
|
||||
|
||||
return rnd & 0x807FFFFFu;
|
||||
}
|
||||
|
||||
protected static ulong GenNormalD()
|
||||
{
|
||||
ulong rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextULong();
|
||||
while (( rnd & 0x7FF0000000000000ul) == 0ul ||
|
||||
(~rnd & 0x7FF0000000000000ul) == 0ul);
|
||||
|
||||
return rnd;
|
||||
}
|
||||
|
||||
protected static ulong GenSubnormalD()
|
||||
{
|
||||
ulong rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextULong();
|
||||
while ((rnd & 0x000FFFFFFFFFFFFFul) == 0ul);
|
||||
|
||||
return rnd & 0x800FFFFFFFFFFFFFul;
|
||||
}
|
||||
}
|
||||
}
|
624
src/Ryujinx.Tests/Cpu/CpuTest32.cs
Normal file
624
src/Ryujinx.Tests/Cpu/CpuTest32.cs
Normal file
|
@ -0,0 +1,624 @@
|
|||
using ARMeilleure;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using NUnit.Framework;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.Tests.Unicorn;
|
||||
using System;
|
||||
using MemoryPermission = Ryujinx.Tests.Unicorn.MemoryPermission;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[TestFixture]
|
||||
public class CpuTest32
|
||||
{
|
||||
protected const uint Size = 0x1000;
|
||||
protected const uint CodeBaseAddress = 0x1000;
|
||||
protected const uint DataBaseAddress = CodeBaseAddress + Size;
|
||||
|
||||
private uint _currAddress;
|
||||
|
||||
private MemoryBlock _ram;
|
||||
|
||||
private MemoryManager _memory;
|
||||
|
||||
private ExecutionContext _context;
|
||||
|
||||
private CpuContext _cpuContext;
|
||||
private UnicornAArch32 _unicornEmu;
|
||||
|
||||
private bool _usingMemory;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_currAddress = CodeBaseAddress;
|
||||
|
||||
_ram = new MemoryBlock(Size * 2);
|
||||
_memory = new MemoryManager(_ram, 1ul << 16);
|
||||
_memory.IncrementReferenceCount();
|
||||
_memory.Map(CodeBaseAddress, 0, Size * 2, MemoryMapFlags.Private);
|
||||
|
||||
_context = CpuContext.CreateExecutionContext();
|
||||
_context.IsAarch32 = true;
|
||||
Translator.IsReadyForTranslation.Set();
|
||||
|
||||
_cpuContext = new CpuContext(_memory, for64Bit: false);
|
||||
|
||||
// Prevent registering LCQ functions in the FunctionTable to avoid initializing and populating the table,
|
||||
// which improves test durations.
|
||||
Optimizations.AllowLcqInFunctionTable = false;
|
||||
Optimizations.UseUnmanagedDispatchLoop = false;
|
||||
|
||||
_unicornEmu = new UnicornAArch32();
|
||||
_unicornEmu.MemoryMap(CodeBaseAddress, Size, MemoryPermission.Read | MemoryPermission.Exec);
|
||||
_unicornEmu.MemoryMap(DataBaseAddress, Size, MemoryPermission.Read | MemoryPermission.Write);
|
||||
_unicornEmu.PC = CodeBaseAddress;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_unicornEmu.Dispose();
|
||||
_unicornEmu = null;
|
||||
|
||||
_memory.DecrementReferenceCount();
|
||||
_context.Dispose();
|
||||
_ram.Dispose();
|
||||
|
||||
_memory = null;
|
||||
_context = null;
|
||||
_cpuContext = null;
|
||||
_unicornEmu = null;
|
||||
|
||||
_usingMemory = false;
|
||||
}
|
||||
|
||||
protected void Reset()
|
||||
{
|
||||
Teardown();
|
||||
Setup();
|
||||
}
|
||||
|
||||
protected void Opcode(uint opcode)
|
||||
{
|
||||
_memory.Write(_currAddress, opcode);
|
||||
|
||||
_unicornEmu.MemoryWrite32(_currAddress, opcode);
|
||||
|
||||
_currAddress += 4;
|
||||
}
|
||||
|
||||
protected void ThumbOpcode(ushort opcode)
|
||||
{
|
||||
_memory.Write(_currAddress, opcode);
|
||||
|
||||
_unicornEmu.MemoryWrite16(_currAddress, opcode);
|
||||
|
||||
_currAddress += 2;
|
||||
}
|
||||
|
||||
protected ExecutionContext GetContext() => _context;
|
||||
|
||||
protected void SetContext(uint r0 = 0,
|
||||
uint r1 = 0,
|
||||
uint r2 = 0,
|
||||
uint r3 = 0,
|
||||
uint sp = 0,
|
||||
V128 v0 = default,
|
||||
V128 v1 = default,
|
||||
V128 v2 = default,
|
||||
V128 v3 = default,
|
||||
V128 v4 = default,
|
||||
V128 v5 = default,
|
||||
V128 v14 = default,
|
||||
V128 v15 = default,
|
||||
bool saturation = false,
|
||||
bool overflow = false,
|
||||
bool carry = false,
|
||||
bool zero = false,
|
||||
bool negative = false,
|
||||
int fpscr = 0,
|
||||
bool thumb = false)
|
||||
{
|
||||
_context.SetX(0, r0);
|
||||
_context.SetX(1, r1);
|
||||
_context.SetX(2, r2);
|
||||
_context.SetX(3, r3);
|
||||
_context.SetX(13, sp);
|
||||
|
||||
_context.SetV(0, v0);
|
||||
_context.SetV(1, v1);
|
||||
_context.SetV(2, v2);
|
||||
_context.SetV(3, v3);
|
||||
_context.SetV(4, v4);
|
||||
_context.SetV(5, v5);
|
||||
_context.SetV(14, v14);
|
||||
_context.SetV(15, v15);
|
||||
|
||||
_context.SetPstateFlag(PState.QFlag, saturation);
|
||||
_context.SetPstateFlag(PState.VFlag, overflow);
|
||||
_context.SetPstateFlag(PState.CFlag, carry);
|
||||
_context.SetPstateFlag(PState.ZFlag, zero);
|
||||
_context.SetPstateFlag(PState.NFlag, negative);
|
||||
|
||||
_context.Fpscr = (FPSCR)fpscr;
|
||||
|
||||
_context.SetPstateFlag(PState.TFlag, thumb);
|
||||
|
||||
_unicornEmu.R[0] = r0;
|
||||
_unicornEmu.R[1] = r1;
|
||||
_unicornEmu.R[2] = r2;
|
||||
_unicornEmu.R[3] = r3;
|
||||
_unicornEmu.SP = sp;
|
||||
|
||||
_unicornEmu.Q[0] = V128ToSimdValue(v0);
|
||||
_unicornEmu.Q[1] = V128ToSimdValue(v1);
|
||||
_unicornEmu.Q[2] = V128ToSimdValue(v2);
|
||||
_unicornEmu.Q[3] = V128ToSimdValue(v3);
|
||||
_unicornEmu.Q[4] = V128ToSimdValue(v4);
|
||||
_unicornEmu.Q[5] = V128ToSimdValue(v5);
|
||||
_unicornEmu.Q[14] = V128ToSimdValue(v14);
|
||||
_unicornEmu.Q[15] = V128ToSimdValue(v15);
|
||||
|
||||
_unicornEmu.QFlag = saturation;
|
||||
_unicornEmu.OverflowFlag = overflow;
|
||||
_unicornEmu.CarryFlag = carry;
|
||||
_unicornEmu.ZeroFlag = zero;
|
||||
_unicornEmu.NegativeFlag = negative;
|
||||
|
||||
_unicornEmu.Fpscr = fpscr;
|
||||
|
||||
_unicornEmu.ThumbFlag = thumb;
|
||||
}
|
||||
|
||||
protected void ExecuteOpcodes(bool runUnicorn = true)
|
||||
{
|
||||
_cpuContext.Execute(_context, CodeBaseAddress);
|
||||
|
||||
if (runUnicorn)
|
||||
{
|
||||
_unicornEmu.RunForCount((_currAddress - CodeBaseAddress - 4) / 4);
|
||||
}
|
||||
}
|
||||
|
||||
protected ExecutionContext SingleOpcode(uint opcode,
|
||||
uint r0 = 0,
|
||||
uint r1 = 0,
|
||||
uint r2 = 0,
|
||||
uint r3 = 0,
|
||||
uint sp = 0,
|
||||
V128 v0 = default,
|
||||
V128 v1 = default,
|
||||
V128 v2 = default,
|
||||
V128 v3 = default,
|
||||
V128 v4 = default,
|
||||
V128 v5 = default,
|
||||
V128 v14 = default,
|
||||
V128 v15 = default,
|
||||
bool saturation = false,
|
||||
bool overflow = false,
|
||||
bool carry = false,
|
||||
bool zero = false,
|
||||
bool negative = false,
|
||||
int fpscr = 0,
|
||||
bool runUnicorn = true)
|
||||
{
|
||||
Opcode(opcode);
|
||||
Opcode(0xE12FFF1E); // BX LR
|
||||
SetContext(r0, r1, r2, r3, sp, v0, v1, v2, v3, v4, v5, v14, v15, saturation, overflow, carry, zero, negative, fpscr);
|
||||
ExecuteOpcodes(runUnicorn);
|
||||
|
||||
return GetContext();
|
||||
}
|
||||
|
||||
protected ExecutionContext SingleThumbOpcode(ushort opcode,
|
||||
uint r0 = 0,
|
||||
uint r1 = 0,
|
||||
uint r2 = 0,
|
||||
uint r3 = 0,
|
||||
uint sp = 0,
|
||||
bool saturation = false,
|
||||
bool overflow = false,
|
||||
bool carry = false,
|
||||
bool zero = false,
|
||||
bool negative = false,
|
||||
int fpscr = 0,
|
||||
bool runUnicorn = true)
|
||||
{
|
||||
ThumbOpcode(opcode);
|
||||
ThumbOpcode(0x4770); // BX LR
|
||||
SetContext(r0, r1, r2, r3, sp, default, default, default, default, default, default, default, default, saturation, overflow, carry, zero, negative, fpscr, thumb: true);
|
||||
ExecuteOpcodes(runUnicorn);
|
||||
|
||||
return GetContext();
|
||||
}
|
||||
|
||||
public void RunPrecomputedTestCase(PrecomputedThumbTestCase test)
|
||||
{
|
||||
foreach (ushort instruction in test.Instructions)
|
||||
{
|
||||
ThumbOpcode(instruction);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
GetContext().SetX(i, test.StartRegs[i]);
|
||||
}
|
||||
|
||||
uint startCpsr = test.StartRegs[15];
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
GetContext().SetPstateFlag((PState)i, (startCpsr & (1u << i)) != 0);
|
||||
}
|
||||
|
||||
ExecuteOpcodes(runUnicorn: false);
|
||||
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
Assert.That(GetContext().GetX(i), Is.EqualTo(test.FinalRegs[i]));
|
||||
}
|
||||
|
||||
uint finalCpsr = test.FinalRegs[15];
|
||||
Assert.That(GetContext().Pstate, Is.EqualTo(finalCpsr));
|
||||
}
|
||||
|
||||
public void RunPrecomputedTestCase(PrecomputedMemoryThumbTestCase test)
|
||||
{
|
||||
byte[] testMem = new byte[Size];
|
||||
|
||||
for (ulong i = 0; i < Size; i += 2)
|
||||
{
|
||||
testMem[i + 0] = (byte)((i + DataBaseAddress) >> 0);
|
||||
testMem[i + 1] = (byte)((i + DataBaseAddress) >> 8);
|
||||
}
|
||||
|
||||
SetWorkingMemory(0, testMem);
|
||||
|
||||
RunPrecomputedTestCase(new PrecomputedThumbTestCase(){
|
||||
Instructions = test.Instructions,
|
||||
StartRegs = test.StartRegs,
|
||||
FinalRegs = test.FinalRegs,
|
||||
});
|
||||
|
||||
foreach (var delta in test.MemoryDelta)
|
||||
{
|
||||
testMem[delta.Address - DataBaseAddress + 0] = (byte)(delta.Value >> 0);
|
||||
testMem[delta.Address - DataBaseAddress + 1] = (byte)(delta.Value >> 8);
|
||||
}
|
||||
|
||||
byte[] mem = _memory.GetSpan(DataBaseAddress, (int)Size).ToArray();
|
||||
|
||||
Assert.That(mem, Is.EqualTo(testMem), "testmem");
|
||||
}
|
||||
|
||||
protected void SetWorkingMemory(uint offset, byte[] data)
|
||||
{
|
||||
_memory.Write(DataBaseAddress + offset, data);
|
||||
|
||||
_unicornEmu.MemoryWrite(DataBaseAddress + offset, data);
|
||||
|
||||
_usingMemory = true; // When true, CompareAgainstUnicorn checks the working memory for equality too.
|
||||
}
|
||||
|
||||
/// <summary>Rounding Mode control field.</summary>
|
||||
public enum RMode
|
||||
{
|
||||
/// <summary>Round to Nearest mode.</summary>
|
||||
Rn,
|
||||
/// <summary>Round towards Plus Infinity mode.</summary>
|
||||
Rp,
|
||||
/// <summary>Round towards Minus Infinity mode.</summary>
|
||||
Rm,
|
||||
/// <summary>Round towards Zero mode.</summary>
|
||||
Rz
|
||||
};
|
||||
|
||||
/// <summary>Floating-point Control Register.</summary>
|
||||
protected enum Fpcr
|
||||
{
|
||||
/// <summary>Rounding Mode control field.</summary>
|
||||
RMode = 22,
|
||||
/// <summary>Flush-to-zero mode control bit.</summary>
|
||||
Fz = 24,
|
||||
/// <summary>Default NaN mode control bit.</summary>
|
||||
Dn = 25,
|
||||
/// <summary>Alternative half-precision control bit.</summary>
|
||||
Ahp = 26
|
||||
}
|
||||
|
||||
/// <summary>Floating-point Status Register.</summary>
|
||||
[Flags]
|
||||
protected enum Fpsr
|
||||
{
|
||||
None = 0,
|
||||
|
||||
/// <summary>Invalid Operation cumulative floating-point exception bit.</summary>
|
||||
Ioc = 1 << 0,
|
||||
/// <summary>Divide by Zero cumulative floating-point exception bit.</summary>
|
||||
Dzc = 1 << 1,
|
||||
/// <summary>Overflow cumulative floating-point exception bit.</summary>
|
||||
Ofc = 1 << 2,
|
||||
/// <summary>Underflow cumulative floating-point exception bit.</summary>
|
||||
Ufc = 1 << 3,
|
||||
/// <summary>Inexact cumulative floating-point exception bit.</summary>
|
||||
Ixc = 1 << 4,
|
||||
/// <summary>Input Denormal cumulative floating-point exception bit.</summary>
|
||||
Idc = 1 << 7,
|
||||
|
||||
/// <summary>Cumulative saturation bit.</summary>
|
||||
Qc = 1 << 27,
|
||||
|
||||
/// <summary>NZCV flags.</summary>
|
||||
Nzcv = (1 << 31) | (1 << 30) | (1 << 29) | (1 << 28)
|
||||
}
|
||||
|
||||
[Flags]
|
||||
protected enum FpSkips
|
||||
{
|
||||
None = 0,
|
||||
|
||||
IfNaNS = 1,
|
||||
IfNaND = 2,
|
||||
|
||||
IfUnderflow = 4,
|
||||
IfOverflow = 8
|
||||
}
|
||||
|
||||
protected enum FpTolerances
|
||||
{
|
||||
None,
|
||||
|
||||
UpToOneUlpsS,
|
||||
UpToOneUlpsD
|
||||
}
|
||||
|
||||
protected void CompareAgainstUnicorn(
|
||||
Fpsr fpsrMask = Fpsr.None,
|
||||
FpSkips fpSkips = FpSkips.None,
|
||||
FpTolerances fpTolerances = FpTolerances.None)
|
||||
{
|
||||
if (fpSkips != FpSkips.None)
|
||||
{
|
||||
ManageFpSkips(fpSkips);
|
||||
}
|
||||
|
||||
Assert.That(_context.GetX(0), Is.EqualTo(_unicornEmu.R[0]), "R0");
|
||||
Assert.That(_context.GetX(1), Is.EqualTo(_unicornEmu.R[1]), "R1");
|
||||
Assert.That(_context.GetX(2), Is.EqualTo(_unicornEmu.R[2]), "R2");
|
||||
Assert.That(_context.GetX(3), Is.EqualTo(_unicornEmu.R[3]), "R3");
|
||||
Assert.That(_context.GetX(4), Is.EqualTo(_unicornEmu.R[4]));
|
||||
Assert.That(_context.GetX(5), Is.EqualTo(_unicornEmu.R[5]));
|
||||
Assert.That(_context.GetX(6), Is.EqualTo(_unicornEmu.R[6]));
|
||||
Assert.That(_context.GetX(7), Is.EqualTo(_unicornEmu.R[7]));
|
||||
Assert.That(_context.GetX(8), Is.EqualTo(_unicornEmu.R[8]));
|
||||
Assert.That(_context.GetX(9), Is.EqualTo(_unicornEmu.R[9]));
|
||||
Assert.That(_context.GetX(10), Is.EqualTo(_unicornEmu.R[10]));
|
||||
Assert.That(_context.GetX(11), Is.EqualTo(_unicornEmu.R[11]));
|
||||
Assert.That(_context.GetX(12), Is.EqualTo(_unicornEmu.R[12]));
|
||||
Assert.That(_context.GetX(13), Is.EqualTo(_unicornEmu.SP), "SP");
|
||||
Assert.That(_context.GetX(14), Is.EqualTo(_unicornEmu.R[14]));
|
||||
|
||||
if (fpTolerances == FpTolerances.None)
|
||||
{
|
||||
Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0]), "V0");
|
||||
}
|
||||
else
|
||||
{
|
||||
ManageFpTolerances(fpTolerances);
|
||||
}
|
||||
Assert.That(V128ToSimdValue(_context.GetV(1)), Is.EqualTo(_unicornEmu.Q[1]), "V1");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(2)), Is.EqualTo(_unicornEmu.Q[2]), "V2");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(3)), Is.EqualTo(_unicornEmu.Q[3]), "V3");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(4)), Is.EqualTo(_unicornEmu.Q[4]), "V4");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(5)), Is.EqualTo(_unicornEmu.Q[5]), "V5");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(6)), Is.EqualTo(_unicornEmu.Q[6]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(7)), Is.EqualTo(_unicornEmu.Q[7]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(8)), Is.EqualTo(_unicornEmu.Q[8]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(9)), Is.EqualTo(_unicornEmu.Q[9]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(10)), Is.EqualTo(_unicornEmu.Q[10]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(11)), Is.EqualTo(_unicornEmu.Q[11]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(12)), Is.EqualTo(_unicornEmu.Q[12]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(13)), Is.EqualTo(_unicornEmu.Q[13]));
|
||||
Assert.That(V128ToSimdValue(_context.GetV(14)), Is.EqualTo(_unicornEmu.Q[14]), "V14");
|
||||
Assert.That(V128ToSimdValue(_context.GetV(15)), Is.EqualTo(_unicornEmu.Q[15]), "V15");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(_context.GetPstateFlag(PState.GE0Flag), Is.EqualTo((_unicornEmu.CPSR & (1u << 16)) != 0), "GE0Flag");
|
||||
Assert.That(_context.GetPstateFlag(PState.GE1Flag), Is.EqualTo((_unicornEmu.CPSR & (1u << 17)) != 0), "GE1Flag");
|
||||
Assert.That(_context.GetPstateFlag(PState.GE2Flag), Is.EqualTo((_unicornEmu.CPSR & (1u << 18)) != 0), "GE2Flag");
|
||||
Assert.That(_context.GetPstateFlag(PState.GE3Flag), Is.EqualTo((_unicornEmu.CPSR & (1u << 19)) != 0), "GE3Flag");
|
||||
Assert.That(_context.GetPstateFlag(PState.QFlag), Is.EqualTo(_unicornEmu.QFlag), "QFlag");
|
||||
Assert.That(_context.GetPstateFlag(PState.VFlag), Is.EqualTo(_unicornEmu.OverflowFlag), "VFlag");
|
||||
Assert.That(_context.GetPstateFlag(PState.CFlag), Is.EqualTo(_unicornEmu.CarryFlag), "CFlag");
|
||||
Assert.That(_context.GetPstateFlag(PState.ZFlag), Is.EqualTo(_unicornEmu.ZeroFlag), "ZFlag");
|
||||
Assert.That(_context.GetPstateFlag(PState.NFlag), Is.EqualTo(_unicornEmu.NegativeFlag), "NFlag");
|
||||
});
|
||||
|
||||
Assert.That((int)_context.Fpscr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpscr & (int)fpsrMask), "Fpscr");
|
||||
|
||||
if (_usingMemory)
|
||||
{
|
||||
byte[] mem = _memory.GetSpan(DataBaseAddress, (int)Size).ToArray();
|
||||
byte[] unicornMem = _unicornEmu.MemoryRead(DataBaseAddress, Size);
|
||||
|
||||
Assert.That(mem, Is.EqualTo(unicornMem), "Data");
|
||||
}
|
||||
}
|
||||
|
||||
private void ManageFpSkips(FpSkips fpSkips)
|
||||
{
|
||||
if (fpSkips.HasFlag(FpSkips.IfNaNS))
|
||||
{
|
||||
if (float.IsNaN(_unicornEmu.Q[0].AsFloat()))
|
||||
{
|
||||
Assert.Ignore("NaN test.");
|
||||
}
|
||||
}
|
||||
else if (fpSkips.HasFlag(FpSkips.IfNaND))
|
||||
{
|
||||
if (double.IsNaN(_unicornEmu.Q[0].AsDouble()))
|
||||
{
|
||||
Assert.Ignore("NaN test.");
|
||||
}
|
||||
}
|
||||
|
||||
if (fpSkips.HasFlag(FpSkips.IfUnderflow))
|
||||
{
|
||||
if ((_unicornEmu.Fpscr & (int)Fpsr.Ufc) != 0)
|
||||
{
|
||||
Assert.Ignore("Underflow test.");
|
||||
}
|
||||
}
|
||||
|
||||
if (fpSkips.HasFlag(FpSkips.IfOverflow))
|
||||
{
|
||||
if ((_unicornEmu.Fpscr & (int)Fpsr.Ofc) != 0)
|
||||
{
|
||||
Assert.Ignore("Overflow test.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ManageFpTolerances(FpTolerances fpTolerances)
|
||||
{
|
||||
bool IsNormalOrSubnormalS(float f) => float.IsNormal(f) || float.IsSubnormal(f);
|
||||
bool IsNormalOrSubnormalD(double d) => double.IsNormal(d) || double.IsSubnormal(d);
|
||||
|
||||
if (!Is.EqualTo(_unicornEmu.Q[0]).ApplyTo(V128ToSimdValue(_context.GetV(0))).IsSuccess)
|
||||
{
|
||||
if (fpTolerances == FpTolerances.UpToOneUlpsS)
|
||||
{
|
||||
if (IsNormalOrSubnormalS(_unicornEmu.Q[0].AsFloat()) &&
|
||||
IsNormalOrSubnormalS(_context.GetV(0).As<float>()))
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(_context.GetV(0).Extract<float>(0),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetFloat(0)).Within(1).Ulps, "V0[0]");
|
||||
Assert.That(_context.GetV(0).Extract<float>(1),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetFloat(1)).Within(1).Ulps, "V0[1]");
|
||||
Assert.That(_context.GetV(0).Extract<float>(2),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetFloat(2)).Within(1).Ulps, "V0[2]");
|
||||
Assert.That(_context.GetV(0).Extract<float>(3),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetFloat(3)).Within(1).Ulps, "V0[3]");
|
||||
});
|
||||
|
||||
Console.WriteLine(fpTolerances);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0]));
|
||||
}
|
||||
}
|
||||
|
||||
if (fpTolerances == FpTolerances.UpToOneUlpsD)
|
||||
{
|
||||
if (IsNormalOrSubnormalD(_unicornEmu.Q[0].AsDouble()) &&
|
||||
IsNormalOrSubnormalD(_context.GetV(0).As<double>()))
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(_context.GetV(0).Extract<double>(0),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetDouble(0)).Within(1).Ulps, "V0[0]");
|
||||
Assert.That(_context.GetV(0).Extract<double>(1),
|
||||
Is.EqualTo(_unicornEmu.Q[0].GetDouble(1)).Within(1).Ulps, "V0[1]");
|
||||
});
|
||||
|
||||
Console.WriteLine(fpTolerances);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SimdValue V128ToSimdValue(V128 value)
|
||||
{
|
||||
return new SimdValue(value.Extract<ulong>(0), value.Extract<ulong>(1));
|
||||
}
|
||||
|
||||
protected static V128 MakeVectorScalar(float value) => new V128(value);
|
||||
protected static V128 MakeVectorScalar(double value) => new V128(value);
|
||||
|
||||
protected static V128 MakeVectorE0(ulong e0) => new V128(e0, 0);
|
||||
protected static V128 MakeVectorE1(ulong e1) => new V128(0, e1);
|
||||
|
||||
protected static V128 MakeVectorE0E1(ulong e0, ulong e1) => new V128(e0, e1);
|
||||
|
||||
protected static V128 MakeVectorE0E1E2E3(uint e0, uint e1, uint e2, uint e3)
|
||||
{
|
||||
return new V128(e0, e1, e2, e3);
|
||||
}
|
||||
|
||||
protected static ulong GetVectorE0(V128 vector) => vector.Extract<ulong>(0);
|
||||
protected static ulong GetVectorE1(V128 vector) => vector.Extract<ulong>(1);
|
||||
|
||||
protected static ushort GenNormalH()
|
||||
{
|
||||
uint rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextUShort();
|
||||
while ((rnd & 0x7C00u) == 0u ||
|
||||
(~rnd & 0x7C00u) == 0u);
|
||||
|
||||
return (ushort)rnd;
|
||||
}
|
||||
|
||||
protected static ushort GenSubnormalH()
|
||||
{
|
||||
uint rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextUShort();
|
||||
while ((rnd & 0x03FFu) == 0u);
|
||||
|
||||
return (ushort)(rnd & 0x83FFu);
|
||||
}
|
||||
|
||||
protected static uint GenNormalS()
|
||||
{
|
||||
uint rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextUInt();
|
||||
while ((rnd & 0x7F800000u) == 0u ||
|
||||
(~rnd & 0x7F800000u) == 0u);
|
||||
|
||||
return rnd;
|
||||
}
|
||||
|
||||
protected static uint GenSubnormalS()
|
||||
{
|
||||
uint rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextUInt();
|
||||
while ((rnd & 0x007FFFFFu) == 0u);
|
||||
|
||||
return rnd & 0x807FFFFFu;
|
||||
}
|
||||
|
||||
protected static ulong GenNormalD()
|
||||
{
|
||||
ulong rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextULong();
|
||||
while ((rnd & 0x7FF0000000000000ul) == 0ul ||
|
||||
(~rnd & 0x7FF0000000000000ul) == 0ul);
|
||||
|
||||
return rnd;
|
||||
}
|
||||
|
||||
protected static ulong GenSubnormalD()
|
||||
{
|
||||
ulong rnd;
|
||||
|
||||
do rnd = TestContext.CurrentContext.Random.NextULong();
|
||||
while ((rnd & 0x000FFFFFFFFFFFFFul) == 0ul);
|
||||
|
||||
return rnd & 0x800FFFFFFFFFFFFFul;
|
||||
}
|
||||
}
|
||||
}
|
266
src/Ryujinx.Tests/Cpu/CpuTestAlu.cs
Normal file
266
src/Ryujinx.Tests/Cpu/CpuTestAlu.cs
Normal file
|
@ -0,0 +1,266 @@
|
|||
#define Alu
|
||||
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Alu")]
|
||||
public sealed class CpuTestAlu : CpuTest
|
||||
{
|
||||
#if Alu
|
||||
|
||||
#region "Helper methods"
|
||||
private static uint GenLeadingSignsMinus32(int cnt) // 0 <= cnt <= 31
|
||||
{
|
||||
return ~GenLeadingZeros32(cnt + 1);
|
||||
}
|
||||
|
||||
private static ulong GenLeadingSignsMinus64(int cnt) // 0 <= cnt <= 63
|
||||
{
|
||||
return ~GenLeadingZeros64(cnt + 1);
|
||||
}
|
||||
|
||||
private static uint GenLeadingSignsPlus32(int cnt) // 0 <= cnt <= 31
|
||||
{
|
||||
return GenLeadingZeros32(cnt + 1);
|
||||
}
|
||||
|
||||
private static ulong GenLeadingSignsPlus64(int cnt) // 0 <= cnt <= 63
|
||||
{
|
||||
return GenLeadingZeros64(cnt + 1);
|
||||
}
|
||||
|
||||
private static uint GenLeadingZeros32(int cnt) // 0 <= cnt <= 32
|
||||
{
|
||||
if (cnt == 32) return 0u;
|
||||
if (cnt == 31) return 1u;
|
||||
|
||||
uint rnd = TestContext.CurrentContext.Random.NextUInt();
|
||||
int mask = int.MinValue;
|
||||
|
||||
return (rnd >> (cnt + 1)) | ((uint)mask >> cnt);
|
||||
}
|
||||
|
||||
private static ulong GenLeadingZeros64(int cnt) // 0 <= cnt <= 64
|
||||
{
|
||||
if (cnt == 64) return 0ul;
|
||||
if (cnt == 63) return 1ul;
|
||||
|
||||
ulong rnd = TestContext.CurrentContext.Random.NextULong();
|
||||
long mask = long.MinValue;
|
||||
|
||||
return (rnd >> (cnt + 1)) | ((ulong)mask >> cnt);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static IEnumerable<ulong> _GenLeadingSignsX_()
|
||||
{
|
||||
for (int cnt = 0; cnt <= 63; cnt++)
|
||||
{
|
||||
yield return GenLeadingSignsMinus64(cnt);
|
||||
yield return GenLeadingSignsPlus64(cnt);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<uint> _GenLeadingSignsW_()
|
||||
{
|
||||
for (int cnt = 0; cnt <= 31; cnt++)
|
||||
{
|
||||
yield return GenLeadingSignsMinus32(cnt);
|
||||
yield return GenLeadingSignsPlus32(cnt);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _GenLeadingZerosX_()
|
||||
{
|
||||
for (int cnt = 0; cnt <= 64; cnt++)
|
||||
{
|
||||
yield return GenLeadingZeros64(cnt);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<uint> _GenLeadingZerosW_()
|
||||
{
|
||||
for (int cnt = 0; cnt <= 32; cnt++)
|
||||
{
|
||||
yield return GenLeadingZeros32(cnt);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Test, Pairwise, Description("CLS <Xd>, <Xn>")]
|
||||
public void Cls_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_GenLeadingSignsX_))] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC01400; // CLS X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CLS <Wd>, <Wn>")]
|
||||
public void Cls_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_GenLeadingSignsW_))] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC01400; // CLS W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CLZ <Xd>, <Xn>")]
|
||||
public void Clz_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_GenLeadingZerosX_))] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC01000; // CLZ X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CLZ <Wd>, <Wn>")]
|
||||
public void Clz_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_GenLeadingZerosW_))] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC01000; // CLZ W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("RBIT <Xd>, <Xn>")]
|
||||
public void Rbit_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC00000; // RBIT X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("RBIT <Wd>, <Wn>")]
|
||||
public void Rbit_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC00000; // RBIT W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("REV16 <Xd>, <Xn>")]
|
||||
public void Rev16_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC00400; // REV16 X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("REV16 <Wd>, <Wn>")]
|
||||
public void Rev16_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC00400; // REV16 W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("REV32 <Xd>, <Xn>")]
|
||||
public void Rev32_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC00800; // REV32 X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("REV <Wd>, <Wn>")]
|
||||
public void Rev32_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
uint opcode = 0x5AC00800; // REV W0, W0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("REV64 <Xd>, <Xn>")]
|
||||
public void Rev64_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn)
|
||||
{
|
||||
uint opcode = 0xDAC00C00; // REV64 X0, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
209
src/Ryujinx.Tests/Cpu/CpuTestAlu32.cs
Normal file
209
src/Ryujinx.Tests/Cpu/CpuTestAlu32.cs
Normal file
|
@ -0,0 +1,209 @@
|
|||
#define Alu32
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Alu32")]
|
||||
public sealed class CpuTestAlu32 : CpuTest32
|
||||
{
|
||||
#if Alu32
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _SU_H_AddSub_8_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe6100f90u, // SADD8 R0, R0, R0
|
||||
0xe6100ff0u, // SSUB8 R0, R0, R0
|
||||
0xe6300f90u, // SHADD8 R0, R0, R0
|
||||
0xe6300ff0u, // SHSUB8 R0, R0, R0
|
||||
0xe6500f90u, // UADD8 R0, R0, R0
|
||||
0xe6500ff0u, // USUB8 R0, R0, R0
|
||||
0xe6700f90u, // UHADD8 R0, R0, R0
|
||||
0xe6700ff0u // UHSUB8 R0, R0, R0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Ssat_Usat_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe6a00010u, // SSAT R0, #1, R0, LSL #0
|
||||
0xe6a00050u, // SSAT R0, #1, R0, ASR #32
|
||||
0xe6e00010u, // USAT R0, #0, R0, LSL #0
|
||||
0xe6e00050u // USAT R0, #0, R0, ASR #32
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Ssat16_Usat16_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe6a00f30u, // SSAT16 R0, #1, R0
|
||||
0xe6e00f30u, // USAT16 R0, #0, R0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Lsr_Lsl_Asr_Ror_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe1b00030u, // LSRS R0, R0, R0
|
||||
0xe1b00010u, // LSLS R0, R0, R0
|
||||
0xe1b00050u, // ASRS R0, R0, R0
|
||||
0xe1b00070u // RORS R0, R0, R0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("RBIT <Rd>, <Rn>")]
|
||||
public void Rbit_32bit([Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
uint opcode = 0xe6ff0f30u; // RBIT R0, R0
|
||||
opcode |= ((rm & 15) << 0) | ((rd & 15) << 12);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r1: wn, sp: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Lsr_Lsl_Asr_Ror([ValueSource(nameof(_Lsr_Lsl_Asr_Ror_))] uint opcode,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint shiftValue,
|
||||
[Range(0, 31)] int shiftAmount)
|
||||
{
|
||||
uint rd = 0;
|
||||
uint rm = 1;
|
||||
uint rs = 2;
|
||||
opcode |= ((rm & 15) << 0) | ((rd & 15) << 12) | ((rs & 15) << 8);
|
||||
|
||||
SingleOpcode(opcode, r1: shiftValue, r2: (uint)shiftAmount);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Shadd8([Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u)] uint rm,
|
||||
[Values(2u)] uint rn,
|
||||
[Random(RndCnt)] uint w0,
|
||||
[Random(RndCnt)] uint w1,
|
||||
[Random(RndCnt)] uint w2)
|
||||
{
|
||||
uint opcode = 0xE6300F90u; // SHADD8 R0, R0, R0
|
||||
|
||||
opcode |= ((rm & 15) << 0) | ((rd & 15) << 12) | ((rn & 15) << 16);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: w0, r1: w1, r2: w2, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Shsub8([Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u)] uint rm,
|
||||
[Values(2u)] uint rn,
|
||||
[Random(RndCnt)] uint w0,
|
||||
[Random(RndCnt)] uint w1,
|
||||
[Random(RndCnt)] uint w2)
|
||||
{
|
||||
uint opcode = 0xE6300FF0u; // SHSUB8 R0, R0, R0
|
||||
|
||||
opcode |= ((rm & 15) << 0) | ((rd & 15) << 12) | ((rn & 15) << 16);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: w0, r1: w1, r2: w2, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Ssat_Usat([ValueSource(nameof(_Ssat_Usat_))] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rn,
|
||||
[Values(0u, 7u, 8u, 0xfu, 0x10u, 0x1fu)] uint sat,
|
||||
[Values(0u, 7u, 8u, 0xfu, 0x10u, 0x1fu)] uint shift,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((shift & 31) << 7) | ((rd & 15) << 12) | ((sat & 31) << 16);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r1: wn, sp: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Ssat16_Usat16([ValueSource(nameof(_Ssat16_Usat16_))] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rn,
|
||||
[Values(0u, 7u, 8u, 0xfu)] uint sat,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rd & 15) << 12) | ((sat & 15) << 16);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r1: wn, sp: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void SU_H_AddSub_8([ValueSource(nameof(_SU_H_AddSub_8_))] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u)] uint rm,
|
||||
[Values(2u)] uint rn,
|
||||
[Random(RndCnt)] uint w0,
|
||||
[Random(RndCnt)] uint w1,
|
||||
[Random(RndCnt)] uint w2)
|
||||
{
|
||||
opcode |= ((rm & 15) << 0) | ((rd & 15) << 12) | ((rn & 15) << 16);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: w0, r1: w1, r2: w2, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Uadd8_Sel([Values(0u)] uint rd,
|
||||
[Values(1u)] uint rm,
|
||||
[Values(2u)] uint rn,
|
||||
[Random(RndCnt)] uint w0,
|
||||
[Random(RndCnt)] uint w1,
|
||||
[Random(RndCnt)] uint w2)
|
||||
{
|
||||
uint opUadd8 = 0xE6500F90; // UADD8 R0, R0, R0
|
||||
uint opSel = 0xE6800FB0; // SEL R0, R0, R0
|
||||
|
||||
opUadd8 |= ((rm & 15) << 0) | ((rd & 15) << 12) | ((rn & 15) << 16);
|
||||
opSel |= ((rm & 15) << 0) | ((rd & 15) << 12) | ((rn & 15) << 16);
|
||||
|
||||
SetContext(r0: w0, r1: w1, r2: w2);
|
||||
Opcode(opUadd8);
|
||||
Opcode(opSel);
|
||||
Opcode(0xE12FFF1E); // BX LR
|
||||
ExecuteOpcodes();
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
307
src/Ryujinx.Tests/Cpu/CpuTestAluBinary.cs
Normal file
307
src/Ryujinx.Tests/Cpu/CpuTestAluBinary.cs
Normal file
|
@ -0,0 +1,307 @@
|
|||
#define AluBinary
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("AluBinary")]
|
||||
public sealed class CpuTestAluBinary : CpuTest
|
||||
{
|
||||
#if AluBinary
|
||||
public struct CrcTest
|
||||
{
|
||||
public uint Crc;
|
||||
public ulong Value;
|
||||
public bool C;
|
||||
|
||||
public uint[] Results; // One result for each CRC variant (8, 16, 32)
|
||||
|
||||
public CrcTest(uint crc, ulong value, bool c, params uint[] results)
|
||||
{
|
||||
Crc = crc;
|
||||
Value = value;
|
||||
C = c;
|
||||
Results = results;
|
||||
}
|
||||
}
|
||||
|
||||
#region "ValueSource (CRC32)"
|
||||
private static CrcTest[] _CRC32_Test_Values_()
|
||||
{
|
||||
// Created with http://www.sunshine2k.de/coding/javascript/crc/crc_js.html, with:
|
||||
// - non-reflected polynomials
|
||||
// - input reflected, result reflected
|
||||
// - bytes in order of increasing significance
|
||||
// - xor 0
|
||||
// Only includes non-C variant, as the other can be tested with unicorn.
|
||||
|
||||
return new[]
|
||||
{
|
||||
new CrcTest(0x00000000u, 0x00_00_00_00_00_00_00_00u, false, 0x00000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
new CrcTest(0x00000000u, 0x7f_ff_ff_ff_ff_ff_ff_ffu, false, 0x2d02ef8d, 0xbe2612ff, 0xdebb20e3, 0xa9de8355),
|
||||
new CrcTest(0x00000000u, 0x80_00_00_00_00_00_00_00u, false, 0x00000000, 0x00000000, 0x00000000, 0xedb88320),
|
||||
new CrcTest(0x00000000u, 0xff_ff_ff_ff_ff_ff_ff_ffu, false, 0x2d02ef8d, 0xbe2612ff, 0xdebb20e3, 0x44660075),
|
||||
new CrcTest(0x00000000u, 0xa0_02_f1_ca_52_78_8c_1cu, false, 0x14015c4f, 0x02799256, 0x9063c9e5, 0x8816610a),
|
||||
|
||||
new CrcTest(0xffffffffu, 0x00_00_00_00_00_00_00_00u, false, 0x2dfd1072, 0xbe26ed00, 0xdebb20e3, 0x9add2096),
|
||||
new CrcTest(0xffffffffu, 0x7f_ff_ff_ff_ff_ff_ff_ffu, false, 0x00ffffff, 0x0000ffff, 0x00000000, 0x3303a3c3),
|
||||
new CrcTest(0xffffffffu, 0x80_00_00_00_00_00_00_00u, false, 0x2dfd1072, 0xbe26ed00, 0xdebb20e3, 0x7765a3b6),
|
||||
new CrcTest(0xffffffffu, 0xff_ff_ff_ff_ff_ff_ff_ffu, false, 0x00ffffff, 0x0000ffff, 0x00000000, 0xdebb20e3),
|
||||
new CrcTest(0xffffffffu, 0xa0_02_f1_ca_52_78_8c_1cu, false, 0x39fc4c3d, 0xbc5f7f56, 0x4ed8e906, 0x12cb419c)
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Test, Combinatorial]
|
||||
public void Crc32_b_h_w_x([Values(0u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[Values(2u)] uint rm,
|
||||
[Range(0u, 3u)] uint size,
|
||||
[ValueSource(nameof(_CRC32_Test_Values_))] CrcTest test)
|
||||
{
|
||||
uint opcode = 0x1AC04000; // CRC32B W0, W0, W0
|
||||
|
||||
opcode |= size << 10;
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
if (size == 3)
|
||||
{
|
||||
opcode |= 0x80000000;
|
||||
}
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: test.Crc, x2: test.Value, x31: w31, runUnicorn: false);
|
||||
|
||||
ExecutionContext context = GetContext();
|
||||
ulong result = context.GetX((int)rd);
|
||||
Assert.That(result == test.Results[size]);
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CRC32X <Wd>, <Wn>, <Xm>"), Ignore("Unicorn fails.")]
|
||||
public void Crc32x([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((ulong)0x00_00_00_00_00_00_00_00,
|
||||
(ulong)0x7F_FF_FF_FF_FF_FF_FF_FF,
|
||||
0x80_00_00_00_00_00_00_00,
|
||||
0xFF_FF_FF_FF_FF_FF_FF_FF)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC04C00; // CRC32X W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: xm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CRC32W <Wd>, <Wn>, <Wm>"), Ignore("Unicorn fails.")]
|
||||
public void Crc32w([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((uint)0x00_00_00_00, (uint)0x7F_FF_FF_FF,
|
||||
0x80_00_00_00, 0xFF_FF_FF_FF)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC04800; // CRC32W W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CRC32H <Wd>, <Wn>, <Wm>"), Ignore("Unicorn fails.")]
|
||||
public void Crc32h([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((ushort)0x00_00, (ushort)0x7F_FF,
|
||||
(ushort)0x80_00, (ushort)0xFF_FF)] ushort wm)
|
||||
{
|
||||
uint opcode = 0x1AC04400; // CRC32H W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CRC32B <Wd>, <Wn>, <Wm>"), Ignore("Unicorn fails.")]
|
||||
public void Crc32b([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm)
|
||||
{
|
||||
uint opcode = 0x1AC04000; // CRC32B W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CRC32CX <Wd>, <Wn>, <Xm>")]
|
||||
public void Crc32cx([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((ulong)0x00_00_00_00_00_00_00_00,
|
||||
(ulong)0x7F_FF_FF_FF_FF_FF_FF_FF,
|
||||
0x80_00_00_00_00_00_00_00,
|
||||
0xFF_FF_FF_FF_FF_FF_FF_FF)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC05C00; // CRC32CX W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: xm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CRC32CW <Wd>, <Wn>, <Wm>")]
|
||||
public void Crc32cw([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((uint)0x00_00_00_00, (uint)0x7F_FF_FF_FF,
|
||||
0x80_00_00_00, 0xFF_FF_FF_FF)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC05800; // CRC32CW W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CRC32CH <Wd>, <Wn>, <Wm>")]
|
||||
public void Crc32ch([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((ushort)0x00_00, (ushort)0x7F_FF,
|
||||
(ushort)0x80_00, (ushort)0xFF_FF)] ushort wm)
|
||||
{
|
||||
uint opcode = 0x1AC05400; // CRC32CH W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CRC32CB <Wd>, <Wn>, <Wm>")]
|
||||
public void Crc32cb([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm)
|
||||
{
|
||||
uint opcode = 0x1AC05000; // CRC32CB W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SDIV <Xd>, <Xn>, <Xm>")]
|
||||
public void Sdiv_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC00C00; // SDIV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SDIV <Wd>, <Wn>, <Wm>")]
|
||||
public void Sdiv_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC00C00; // SDIV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UDIV <Xd>, <Xn>, <Xm>")]
|
||||
public void Udiv_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC00800; // UDIV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UDIV <Wd>, <Wn>, <Wm>")]
|
||||
public void Udiv_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC00800; // UDIV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
95
src/Ryujinx.Tests/Cpu/CpuTestAluBinary32.cs
Normal file
95
src/Ryujinx.Tests/Cpu/CpuTestAluBinary32.cs
Normal file
|
@ -0,0 +1,95 @@
|
|||
#define AluBinary32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
|
||||
[Category("AluBinary32")]
|
||||
public sealed class CpuTestAluBinary32 : CpuTest32
|
||||
{
|
||||
#if AluBinary32
|
||||
public struct CrcTest32
|
||||
{
|
||||
public uint Crc;
|
||||
public uint Value;
|
||||
public bool C;
|
||||
|
||||
public uint[] Results; // One result for each CRC variant (8, 16, 32)
|
||||
|
||||
public CrcTest32(uint crc, uint value, bool c, params uint[] results)
|
||||
{
|
||||
Crc = crc;
|
||||
Value = value;
|
||||
C = c;
|
||||
Results = results;
|
||||
}
|
||||
}
|
||||
|
||||
#region "ValueSource (CRC32/CRC32C)"
|
||||
private static CrcTest32[] _CRC32_Test_Values_()
|
||||
{
|
||||
// Created with http://www.sunshine2k.de/coding/javascript/crc/crc_js.html, with:
|
||||
// - non-reflected polynomials
|
||||
// - input reflected, result reflected
|
||||
// - bytes in order of increasing significance
|
||||
// - xor 0
|
||||
|
||||
return new[]
|
||||
{
|
||||
new CrcTest32(0x00000000u, 0x00_00_00_00u, false, 0x00000000, 0x00000000, 0x00000000),
|
||||
new CrcTest32(0x00000000u, 0x7f_ff_ff_ffu, false, 0x2d02ef8d, 0xbe2612ff, 0x3303a3c3),
|
||||
new CrcTest32(0x00000000u, 0x80_00_00_00u, false, 0x00000000, 0x00000000, 0xedb88320),
|
||||
new CrcTest32(0x00000000u, 0xff_ff_ff_ffu, false, 0x2d02ef8d, 0xbe2612ff, 0xdebb20e3),
|
||||
new CrcTest32(0x00000000u, 0x9d_cb_12_f0u, false, 0xbdbdf21c, 0xe70590f5, 0x3f7480c5),
|
||||
|
||||
new CrcTest32(0xffffffffu, 0x00_00_00_00u, false, 0x2dfd1072, 0xbe26ed00, 0xdebb20e3),
|
||||
new CrcTest32(0xffffffffu, 0x7f_ff_ff_ffu, false, 0x00ffffff, 0x0000ffff, 0xedb88320),
|
||||
new CrcTest32(0xffffffffu, 0x80_00_00_00u, false, 0x2dfd1072, 0xbe26ed00, 0x3303a3c3),
|
||||
new CrcTest32(0xffffffffu, 0xff_ff_ff_ffu, false, 0x00ffffff, 0x0000ffff, 0x00000000),
|
||||
new CrcTest32(0xffffffffu, 0x9d_cb_12_f0u, false, 0x9040e26e, 0x59237df5, 0xe1cfa026),
|
||||
|
||||
new CrcTest32(0x00000000u, 0x00_00_00_00u, true, 0x00000000, 0x00000000, 0x00000000),
|
||||
new CrcTest32(0x00000000u, 0x7f_ff_ff_ffu, true, 0xad7d5351, 0x0e9e77d2, 0x356e8f40),
|
||||
new CrcTest32(0x00000000u, 0x80_00_00_00u, true, 0x00000000, 0x00000000, 0x82f63b78),
|
||||
new CrcTest32(0x00000000u, 0xff_ff_ff_ffu, true, 0xad7d5351, 0x0e9e77d2, 0xb798b438),
|
||||
new CrcTest32(0x00000000u, 0x9d_cb_12_f0u, true, 0xf36e6f75, 0xb5ff99e6, 0x782dfbf1),
|
||||
|
||||
new CrcTest32(0xffffffffu, 0x00_00_00_00u, true, 0xad82acae, 0x0e9e882d, 0xb798b438),
|
||||
new CrcTest32(0xffffffffu, 0x7f_ff_ff_ffu, true, 0x00ffffff, 0x0000ffff, 0x82f63b78),
|
||||
new CrcTest32(0xffffffffu, 0x80_00_00_00u, true, 0xad82acae, 0x0e9e882d, 0x356e8f40),
|
||||
new CrcTest32(0xffffffffu, 0xff_ff_ff_ffu, true, 0x00ffffff, 0x0000ffff, 0x00000000),
|
||||
new CrcTest32(0xffffffffu, 0x9d_cb_12_f0u, true, 0x5eecc3db, 0xbb6111cb, 0xcfb54fc9)
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Test, Combinatorial]
|
||||
public void Crc32_Crc32c_b_h_w([Values(0u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[Values(2u)] uint rm,
|
||||
[Range(0u, 2u)] uint size,
|
||||
[ValueSource(nameof(_CRC32_Test_Values_))] CrcTest32 test)
|
||||
{
|
||||
// Unicorn does not yet support 32bit crc instructions, so test against a known table of results/values.
|
||||
|
||||
uint opcode = 0xe1000040; // CRC32B R0, R0, R0
|
||||
opcode |= ((rm & 15) << 0) | ((rd & 15) << 12) | ((rn & 15) << 16);
|
||||
opcode |= size << 21;
|
||||
if (test.C)
|
||||
{
|
||||
opcode |= 1 << 9;
|
||||
}
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r1: test.Crc, r2: test.Value, sp: sp, runUnicorn: false);
|
||||
|
||||
ExecutionContext context = GetContext();
|
||||
ulong result = context.GetX((int)rd);
|
||||
Assert.That(result == test.Results[size]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
433
src/Ryujinx.Tests/Cpu/CpuTestAluImm.cs
Normal file
433
src/Ryujinx.Tests/Cpu/CpuTestAluImm.cs
Normal file
|
@ -0,0 +1,433 @@
|
|||
#define AluImm
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("AluImm")]
|
||||
public sealed class CpuTestAluImm : CpuTest
|
||||
{
|
||||
#if AluImm
|
||||
|
||||
[Test, Pairwise, Description("ADD <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}")]
|
||||
public void Add_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x91000000; // ADD X0, X0, #0, LSL #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
SingleOpcode(opcode, x1: xnSp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Wd|WSP>, <Wn|WSP>, #<imm>{, <shift>}")]
|
||||
public void Add_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x11000000; // ADD W0, W0, #0, LSL #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
SingleOpcode(opcode, x1: wnWsp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Xd>, <Xn|SP>, #<imm>{, <shift>}")]
|
||||
public void Adds_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0xB1000000; // ADDS X0, X0, #0, LSL #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
SingleOpcode(opcode, x1: xnSp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Wd>, <Wn|WSP>, #<imm>{, <shift>}")]
|
||||
public void Adds_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x31000000; // ADDS W0, W0, #0, LSL #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
SingleOpcode(opcode, x1: wnWsp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("AND <Xd|SP>, <Xn>, #<imm>")]
|
||||
public void And_N1_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x92400000; // AND X0, X0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("AND <Xd|SP>, <Xn>, #<imm>")]
|
||||
public void And_N0_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x92000000; // AND X0, X0, #0x100000001
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("AND <Wd|WSP>, <Wn>, #<imm>")]
|
||||
public void And_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x12000000; // AND W0, W0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ANDS <Xd>, <Xn>, #<imm>")]
|
||||
public void Ands_N1_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xF2400000; // ANDS X0, X0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ANDS <Xd>, <Xn>, #<imm>")]
|
||||
public void Ands_N0_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xF2000000; // ANDS X0, X0, #0x100000001
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ANDS <Wd>, <Wn>, #<imm>")]
|
||||
public void Ands_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x72000000; // ANDS W0, W0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EOR <Xd|SP>, <Xn>, #<imm>")]
|
||||
public void Eor_N1_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xD2400000; // EOR X0, X0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EOR <Xd|SP>, <Xn>, #<imm>")]
|
||||
public void Eor_N0_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xD2000000; // EOR X0, X0, #0x100000001
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EOR <Wd>, <Wn>, #<imm>")]
|
||||
public void Eor_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x52000000; // EOR W0, W0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ORR <Xd|SP>, <Xn>, #<imm>")]
|
||||
public void Orr_N1_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 62u)] uint imms, // <imm>
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xB2400000; // ORR X0, X0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ORR <Xd|SP>, <Xn>, #<imm>")]
|
||||
public void Orr_N0_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0xB2000000; // ORR X0, X0, #0x100000001
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ORR <Wd|WSP>, <Wn>, #<imm>")]
|
||||
public void Orr_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 30u)] uint imms, // <imm>
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr) // <imm>
|
||||
{
|
||||
uint opcode = 0x32000000; // ORR W0, W0, #0x1
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}")]
|
||||
public void Sub_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0xD1000000; // SUB X0, X0, #0, LSL #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
SingleOpcode(opcode, x1: xnSp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Wd|WSP>, <Wn|WSP>, #<imm>{, <shift>}")]
|
||||
public void Sub_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x51000000; // SUB W0, W0, #0, LSL #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
SingleOpcode(opcode, x1: wnWsp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Xd>, <Xn|SP>, #<imm>{, <shift>}")]
|
||||
public void Subs_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0xF1000000; // SUBS X0, X0, #0, LSL #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
SingleOpcode(opcode, x1: xnSp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Wd>, <Wn|WSP>, #<imm>{, <shift>}")]
|
||||
public void Subs_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift) // <LSL #0, LSL #12>
|
||||
{
|
||||
uint opcode = 0x71000000; // SUBS W0, W0, #0, LSL #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
SingleOpcode(opcode, x1: wnWsp);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
55
src/Ryujinx.Tests/Cpu/CpuTestAluImm32.cs
Normal file
55
src/Ryujinx.Tests/Cpu/CpuTestAluImm32.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
#define AluRs32
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("AluImm32")]
|
||||
public sealed class CpuTestAluImm32 : CpuTest32
|
||||
{
|
||||
#if AluRs32
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _opcodes()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe2a00000u, // ADC R0, R0, #0
|
||||
0xe2b00000u, // ADCS R0, R0, #0
|
||||
0xe2800000u, // ADD R0, R0, #0
|
||||
0xe2900000u, // ADDS R0, R0, #0
|
||||
0xe3c00000u, // BIC R0, R0, #0
|
||||
0xe3d00000u, // BICS R0, R0, #0
|
||||
0xe2600000u, // RSB R0, R0, #0
|
||||
0xe2700000u, // RSBS R0, R0, #0
|
||||
0xe2e00000u, // RSC R0, R0, #0
|
||||
0xe2f00000u, // RSCS R0, R0, #0
|
||||
0xe2c00000u, // SBC R0, R0, #0
|
||||
0xe2d00000u, // SBCS R0, R0, #0
|
||||
0xe2400000u, // SUB R0, R0, #0
|
||||
0xe2500000u, // SUBS R0, R0, #0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void TestCpuTestAluImm32([ValueSource(nameof(_opcodes))] uint opcode,
|
||||
[Values(0u, 13u)] uint rd,
|
||||
[Values(1u, 13u)] uint rn,
|
||||
[Random(RndCnt)] uint imm,
|
||||
[Random(RndCnt)] uint wn,
|
||||
[Values(true, false)] bool carryIn)
|
||||
{
|
||||
opcode |= ((imm & 0xfff) << 0) | ((rn & 15) << 16) | ((rd & 15) << 12);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r1: wn, sp: sp, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
895
src/Ryujinx.Tests/Cpu/CpuTestAluRs.cs
Normal file
895
src/Ryujinx.Tests/Cpu/CpuTestAluRs.cs
Normal file
|
@ -0,0 +1,895 @@
|
|||
#define AluRs
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("AluRs")]
|
||||
public sealed class CpuTestAluRs : CpuTest
|
||||
{
|
||||
#if AluRs
|
||||
|
||||
[Test, Pairwise, Description("ADC <Xd>, <Xn>, <Xm>")]
|
||||
public void Adc_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x9A000000; // ADC X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADC <Wd>, <Wn>, <Wm>")]
|
||||
public void Adc_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x1A000000; // ADC W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADCS <Xd>, <Xn>, <Xm>")]
|
||||
public void Adcs_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0xBA000000; // ADCS X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADCS <Wd>, <Wn>, <Wm>")]
|
||||
public void Adcs_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x3A000000; // ADCS W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Add_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8B000000; // ADD X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Add_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x0B000000; // ADD W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Adds_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAB000000; // ADDS X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Adds_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x2B000000; // ADDS W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("AND <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void And_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8A000000; // AND X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("AND <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void And_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x0A000000; // AND W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ANDS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Ands_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEA000000; // ANDS X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ANDS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Ands_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x6A000000; // ANDS W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ASRV <Xd>, <Xn>, <Xm>")]
|
||||
public void Asrv_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0ul, 31ul, 32ul, 63ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC02800; // ASRV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ASRV <Wd>, <Wn>, <Wm>")]
|
||||
public void Asrv_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC02800; // ASRV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BIC <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Bic_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8A200000; // BIC X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BIC <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Bic_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x0A200000; // BIC W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BICS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Bics_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEA200000; // BICS X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BICS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Bics_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x6A200000; // BICS W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EON <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Eon_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCA200000; // EON X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EON <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Eon_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x4A200000; // EON W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EOR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Eor_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCA000000; // EOR X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EOR <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Eor_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x4A000000; // EOR W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EXTR <Xd>, <Xn>, <Xm>, #<lsb>")]
|
||||
public void Extr_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0u, 31u, 32u, 63u)] uint lsb)
|
||||
{
|
||||
uint opcode = 0x93C00000; // EXTR X0, X0, X0, #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((lsb & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EXTR <Wd>, <Wn>, <Wm>, #<lsb>")]
|
||||
public void Extr_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb)
|
||||
{
|
||||
uint opcode = 0x13800000; // EXTR W0, W0, W0, #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((lsb & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("LSLV <Xd>, <Xn>, <Xm>")]
|
||||
public void Lslv_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0ul, 31ul, 32ul, 63ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC02000; // LSLV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("LSLV <Wd>, <Wn>, <Wm>")]
|
||||
public void Lslv_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC02000; // LSLV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("LSRV <Xd>, <Xn>, <Xm>")]
|
||||
public void Lsrv_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0ul, 31ul, 32ul, 63ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC02400; // LSRV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("LSRV <Wd>, <Wn>, <Wm>")]
|
||||
public void Lsrv_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC02400; // LSRV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ORN <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Orn_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAA200000; // ORN X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ORN <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Orn_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x2A200000; // ORN W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ORR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Orr_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAA000000; // ORR X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ORR <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Orr_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x2A000000; // ORR W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("RORV <Xd>, <Xn>, <Xm>")]
|
||||
public void Rorv_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0ul, 31ul, 32ul, 63ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9AC02C00; // RORV X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("RORV <Wd>, <Wn>, <Wm>")]
|
||||
public void Rorv_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
uint opcode = 0x1AC02C00; // RORV W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SBC <Xd>, <Xn>, <Xm>")]
|
||||
public void Sbc_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0xDA000000; // SBC X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SBC <Wd>, <Wn>, <Wm>")]
|
||||
public void Sbc_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x5A000000; // SBC W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SBCS <Xd>, <Xn>, <Xm>")]
|
||||
public void Sbcs_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0xFA000000; // SBCS X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SBCS <Wd>, <Wn>, <Wm>")]
|
||||
public void Sbcs_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
uint opcode = 0x7A000000; // SBCS W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Sub_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCB000000; // SUB X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Sub_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x4B000000; // SUB W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}")]
|
||||
public void Subs_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 31u, 32u, 63u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEB000000; // SUBS X0, X0, X0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}")]
|
||||
public void Subs_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint shift, // <LSL, LSR, ASR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x6B000000; // SUBS W0, W0, W0, LSL #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((shift & 3) << 22) | ((amount & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
82
src/Ryujinx.Tests/Cpu/CpuTestAluRs32.cs
Normal file
82
src/Ryujinx.Tests/Cpu/CpuTestAluRs32.cs
Normal file
|
@ -0,0 +1,82 @@
|
|||
#define AluRs32
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("AluRs32")]
|
||||
public sealed class CpuTestAluRs32 : CpuTest32
|
||||
{
|
||||
#if AluRs32
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Add_Adds_Rsb_Rsbs_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe0800000u, // ADD R0, R0, R0, LSL #0
|
||||
0xe0900000u, // ADDS R0, R0, R0, LSL #0
|
||||
0xe0600000u, // RSB R0, R0, R0, LSL #0
|
||||
0xe0700000u // RSBS R0, R0, R0, LSL #0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Adc_Adcs_Rsc_Rscs_Sbc_Sbcs_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe0a00000u, // ADC R0, R0, R0
|
||||
0xe0b00000u, // ADCS R0, R0, R0
|
||||
0xe0e00000u, // RSC R0, R0, R0
|
||||
0xe0f00000u, // RSCS R0, R0, R0
|
||||
0xe0c00000u, // SBC R0, R0, R0
|
||||
0xe0d00000u // SBCS R0, R0, R0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Adc_Adcs_Rsc_Rscs_Sbc_Sbcs([ValueSource("_Adc_Adcs_Rsc_Rscs_Sbc_Sbcs_")] uint opcode,
|
||||
[Values(0u, 13u)] uint rd,
|
||||
[Values(1u, 13u)] uint rn,
|
||||
[Values(2u, 13u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values] bool carryIn)
|
||||
{
|
||||
opcode |= ((rm & 15) << 0) | ((rn & 15) << 16) | ((rd & 15) << 12);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r1: wn, r2: wm, sp: sp, carry: carryIn);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Add_Adds_Rsb_Rsbs([ValueSource("_Add_Adds_Rsb_Rsbs_")] uint opcode,
|
||||
[Values(0u, 13u)] uint rd,
|
||||
[Values(1u, 13u)] uint rn,
|
||||
[Values(2u, 13u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint shift, // <LSL, LSR, ASR, ROR>
|
||||
[Values(0u, 15u, 16u, 31u)] uint amount)
|
||||
{
|
||||
opcode |= ((rm & 15) << 0) | ((rn & 15) << 16) | ((rd & 15) << 12);
|
||||
opcode |= ((shift & 3) << 5) | ((amount & 31) << 7);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r1: wn, r2: wm, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
723
src/Ryujinx.Tests/Cpu/CpuTestAluRx.cs
Normal file
723
src/Ryujinx.Tests/Cpu/CpuTestAluRx.cs
Normal file
|
@ -0,0 +1,723 @@
|
|||
#define AluRx
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("AluRx")]
|
||||
public sealed class CpuTestAluRx : CpuTest
|
||||
{
|
||||
#if AluRx
|
||||
|
||||
[Test, Pairwise, Description("ADD <Xd|SP>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
||||
public void Add_X_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ulong)0x0000000000000000, (ulong)0x7FFFFFFFFFFFFFFF,
|
||||
0x8000000000000000, 0xFFFFFFFFFFFFFFFF)] ulong xm,
|
||||
[Values(0b011u, 0b111u)] uint extend, // <LSL|UXTX, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8B206000; // ADD X0, X0, X0, UXTX #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: xm, x31: x31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp, x2: xm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Add_W_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8B200000; // ADD X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: x31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Add_H_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8B200000; // ADD X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: x31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Add_B_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x8B200000; // ADD X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: x31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Add_W_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x0B200000; // ADD W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: w31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Add_H_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x0B200000; // ADD W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: w31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Add_B_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x0B200000; // ADD W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: w31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Xd>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
||||
public void Adds_X_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ulong)0x0000000000000000, (ulong)0x7FFFFFFFFFFFFFFF,
|
||||
0x8000000000000000, 0xFFFFFFFFFFFFFFFF)] ulong xm,
|
||||
[Values(0b011u, 0b111u)] uint extend, // <LSL|UXTX, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAB206000; // ADDS X0, X0, X0, UXTX #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: xm, x31: xnSp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Adds_W_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAB200000; // ADDS X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: xnSp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Adds_H_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAB200000; // ADDS X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: xnSp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Adds_B_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xAB200000; // ADDS X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: xnSp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Adds_W_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x2B200000; // ADDS W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: wnWsp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Adds_H_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x2B200000; // ADDS W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: wnWsp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Adds_B_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x2B200000; // ADDS W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: wnWsp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Xd|SP>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
||||
public void Sub_X_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ulong)0x0000000000000000, (ulong)0x7FFFFFFFFFFFFFFF,
|
||||
0x8000000000000000, 0xFFFFFFFFFFFFFFFF)] ulong xm,
|
||||
[Values(0b011u, 0b111u)] uint extend, // <LSL|UXTX, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCB206000; // SUB X0, X0, X0, UXTX #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: xm, x31: x31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp, x2: xm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Sub_W_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCB200000; // SUB X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: x31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Sub_H_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCB200000; // SUB X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: x31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Xd|SP>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Sub_B_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xCB200000; // SUB X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: x31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: xnSp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Sub_W_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x4B200000; // SUB W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: w31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Sub_H_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x4B200000; // SUB W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: w31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Sub_B_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x4B200000; // SUB W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
if (rn != 31)
|
||||
{
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: w31);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleOpcode(opcode, x31: wnWsp, x2: wm);
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Xd>, <Xn|SP>, <X><m>{, <extend> {#<amount>}}")]
|
||||
public void Subs_X_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ulong)0x0000000000000000, (ulong)0x7FFFFFFFFFFFFFFF,
|
||||
0x8000000000000000, 0xFFFFFFFFFFFFFFFF)] ulong xm,
|
||||
[Values(0b011u, 0b111u)] uint extend, // <LSL|UXTX, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEB206000; // SUBS X0, X0, X0, UXTX #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: xm, x31: xnSp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Subs_W_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEB200000; // SUBS X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: xnSp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Subs_H_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEB200000; // SUBS X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: xnSp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Xd>, <Xn|SP>, <W><m>{, <extend> {#<amount>}}")]
|
||||
public void Subs_B_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xnSp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, // <UXTB, UXTH, UXTW,
|
||||
0b100u, 0b101u, 0b110u)] uint extend, // SXTB, SXTH, SXTW>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0xEB200000; // SUBS X0, X0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: xnSp, x2: wm, x31: xnSp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Subs_W_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((uint)0x00000000, (uint)0x7FFFFFFF,
|
||||
0x80000000, 0xFFFFFFFF)] uint wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x6B200000; // SUBS W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: wnWsp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Subs_H_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((ushort)0x0000, (ushort)0x7FFF,
|
||||
(ushort)0x8000, (ushort)0xFFFF)] ushort wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x6B200000; // SUBS W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: wnWsp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUBS <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}")]
|
||||
public void Subs_B_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wnWsp,
|
||||
[Values((byte)0x00, (byte)0x7F,
|
||||
(byte)0x80, (byte)0xFF)] byte wm,
|
||||
[Values(0b000u, 0b001u, 0b010u, 0b011u, // <UXTB, UXTH, LSL|UXTW, UXTX,
|
||||
0b100u, 0b101u, 0b110u, 0b111u)] uint extend, // SXTB, SXTH, SXTW, SXTX>
|
||||
[Values(0u, 1u, 2u, 3u, 4u)] uint amount)
|
||||
{
|
||||
uint opcode = 0x6B200000; // SUBS W0, W0, W0, UXTB #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((extend & 7) << 13) | ((amount & 7) << 10);
|
||||
|
||||
SingleOpcode(opcode, x1: wnWsp, x2: wm, x31: wnWsp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
106
src/Ryujinx.Tests/Cpu/CpuTestBf32.cs
Normal file
106
src/Ryujinx.Tests/Cpu/CpuTestBf32.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
#define Bf32
|
||||
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Bf32")]
|
||||
public sealed class CpuTestBf32 : CpuTest32
|
||||
{
|
||||
#if Bf32
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("BFC <Rd>, #<lsb>, #<width>")]
|
||||
public void Bfc([Values(0u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wd,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] uint msb)
|
||||
{
|
||||
msb = Math.Max(lsb, msb); // Don't test unpredictable for now.
|
||||
uint opcode = 0xe7c0001fu; // BFC R0, #0, #1
|
||||
opcode |= ((rd & 0xf) << 12);
|
||||
opcode |= ((msb & 31) << 16) | ((lsb & 31) << 7);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wd, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BFI <Rd>, <Rn>, #<lsb>, #<width>")]
|
||||
public void Bfi([Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rn,
|
||||
[Random(RndCnt)] uint wd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] uint msb)
|
||||
{
|
||||
msb = Math.Max(lsb, msb); // Don't test unpredictable for now.
|
||||
uint opcode = 0xe7c00010u; // BFI R0, R0, #0, #1
|
||||
opcode |= ((rd & 0xf) << 12);
|
||||
opcode |= ((rn & 0xf) << 0);
|
||||
opcode |= ((msb & 31) << 16) | ((lsb & 31) << 7);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wd, r1: wn, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UBFX <Rd>, <Rn>, #<lsb>, #<width>")]
|
||||
public void Ubfx([Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rn,
|
||||
[Random(RndCnt)] uint wd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] uint widthm1)
|
||||
{
|
||||
if (lsb + widthm1 > 31)
|
||||
{
|
||||
widthm1 -= (lsb + widthm1) - 31;
|
||||
}
|
||||
uint opcode = 0xe7e00050u; // UBFX R0, R0, #0, #1
|
||||
opcode |= ((rd & 0xf) << 12);
|
||||
opcode |= ((rn & 0xf) << 0);
|
||||
opcode |= ((widthm1 & 31) << 16) | ((lsb & 31) << 7);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wd, r1: wn, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SBFX <Rd>, <Rn>, #<lsb>, #<width>")]
|
||||
public void Sbfx([Values(0u, 0xdu)] uint rd,
|
||||
[Values(1u, 0xdu)] uint rn,
|
||||
[Random(RndCnt)] uint wd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint lsb,
|
||||
[Values(0u, 15u, 16u, 31u)] uint widthm1)
|
||||
{
|
||||
if (lsb + widthm1 > 31)
|
||||
{
|
||||
widthm1 -= (lsb + widthm1) - 31;
|
||||
}
|
||||
uint opcode = 0xe7a00050u; // SBFX R0, R0, #0, #1
|
||||
opcode |= ((rd & 0xf) << 12);
|
||||
opcode |= ((rn & 0xf) << 0);
|
||||
opcode |= ((widthm1 & 31) << 16) | ((lsb & 31) << 7);
|
||||
|
||||
uint sp = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wd, r1: wn, sp: sp);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
130
src/Ryujinx.Tests/Cpu/CpuTestBfm.cs
Normal file
130
src/Ryujinx.Tests/Cpu/CpuTestBfm.cs
Normal file
|
@ -0,0 +1,130 @@
|
|||
#define Bfm
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Bfm")]
|
||||
public sealed class CpuTestBfm : CpuTest
|
||||
{
|
||||
#if Bfm
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("BFM <Xd>, <Xn>, #<immr>, #<imms>")]
|
||||
public void Bfm_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Random(RndCnt)] ulong xd,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr,
|
||||
[Values(0u, 31u, 32u, 63u)] uint imms)
|
||||
{
|
||||
uint opcode = 0xB3400000; // BFM X0, X0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x0: xd, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BFM <Wd>, <Wn>, #<immr>, #<imms>")]
|
||||
public void Bfm_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Random(RndCnt)] uint wd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr,
|
||||
[Values(0u, 15u, 16u, 31u)] uint imms)
|
||||
{
|
||||
uint opcode = 0x33000000; // BFM W0, W0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x0: wd, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SBFM <Xd>, <Xn>, #<immr>, #<imms>")]
|
||||
public void Sbfm_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr,
|
||||
[Values(0u, 31u, 32u, 63u)] uint imms)
|
||||
{
|
||||
uint opcode = 0x93400000; // SBFM X0, X0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SBFM <Wd>, <Wn>, #<immr>, #<imms>")]
|
||||
public void Sbfm_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr,
|
||||
[Values(0u, 15u, 16u, 31u)] uint imms)
|
||||
{
|
||||
uint opcode = 0x13000000; // SBFM W0, W0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UBFM <Xd>, <Xn>, #<immr>, #<imms>")]
|
||||
public void Ubfm_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u, 32u, 63u)] uint immr,
|
||||
[Values(0u, 31u, 32u, 63u)] uint imms)
|
||||
{
|
||||
uint opcode = 0xD3400000; // UBFM X0, X0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UBFM <Wd>, <Wn>, #<immr>, #<imms>")]
|
||||
public void Ubfm_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 15u, 16u, 31u)] uint immr,
|
||||
[Values(0u, 15u, 16u, 31u)] uint imms)
|
||||
{
|
||||
uint opcode = 0x53000000; // UBFM W0, W0, #0, #0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((immr & 63) << 16) | ((imms & 63) << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
102
src/Ryujinx.Tests/Cpu/CpuTestCcmpImm.cs
Normal file
102
src/Ryujinx.Tests/Cpu/CpuTestCcmpImm.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
#define CcmpImm
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("CcmpImm")]
|
||||
public sealed class CpuTestCcmpImm : CpuTest
|
||||
{
|
||||
#if CcmpImm
|
||||
private const int RndCntNzcv = 2;
|
||||
|
||||
[Test, Pairwise, Description("CCMN <Xn>, #<imm>, #<nzcv>, <cond>")]
|
||||
public void Ccmn_64bit([Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u)] uint imm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0xBA400800; // CCMN X0, #0, #0, EQ
|
||||
opcode |= ((rn & 31) << 5);
|
||||
opcode |= ((imm & 31) << 16) | ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CCMN <Wn>, #<imm>, #<nzcv>, <cond>")]
|
||||
public void Ccmn_32bit([Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 31u)] uint imm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x3A400800; // CCMN W0, #0, #0, EQ
|
||||
opcode |= ((rn & 31) << 5);
|
||||
opcode |= ((imm & 31) << 16) | ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CCMP <Xn>, #<imm>, #<nzcv>, <cond>")]
|
||||
public void Ccmp_64bit([Values(1u, 31u)] uint rn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 31u)] uint imm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0xFA400800; // CCMP X0, #0, #0, EQ
|
||||
opcode |= ((rn & 31) << 5);
|
||||
opcode |= ((imm & 31) << 16) | ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CCMP <Wn>, #<imm>, #<nzcv>, <cond>")]
|
||||
public void Ccmp_32bit([Values(1u, 31u)] uint rn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 31u)] uint imm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x7A400800; // CCMP W0, #0, #0, EQ
|
||||
opcode |= ((rn & 31) << 5);
|
||||
opcode |= ((imm & 31) << 16) | ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
110
src/Ryujinx.Tests/Cpu/CpuTestCcmpReg.cs
Normal file
110
src/Ryujinx.Tests/Cpu/CpuTestCcmpReg.cs
Normal file
|
@ -0,0 +1,110 @@
|
|||
#define CcmpReg
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("CcmpReg")]
|
||||
public sealed class CpuTestCcmpReg : CpuTest
|
||||
{
|
||||
#if CcmpReg
|
||||
private const int RndCntNzcv = 2;
|
||||
|
||||
[Test, Pairwise, Description("CCMN <Xn>, <Xm>, #<nzcv>, <cond>")]
|
||||
public void Ccmn_64bit([Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0xBA400000; // CCMN X0, X0, #0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5);
|
||||
opcode |= ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CCMN <Wn>, <Wm>, #<nzcv>, <cond>")]
|
||||
public void Ccmn_32bit([Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x3A400000; // CCMN W0, W0, #0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5);
|
||||
opcode |= ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CCMP <Xn>, <Xm>, #<nzcv>, <cond>")]
|
||||
public void Ccmp_64bit([Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0xFA400000; // CCMP X0, X0, #0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5);
|
||||
opcode |= ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CCMP <Wn>, <Wm>, #<nzcv>, <cond>")]
|
||||
public void Ccmp_32bit([Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x7A400000; // CCMP W0, W0, #0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5);
|
||||
opcode |= ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
205
src/Ryujinx.Tests/Cpu/CpuTestCsel.cs
Normal file
205
src/Ryujinx.Tests/Cpu/CpuTestCsel.cs
Normal file
|
@ -0,0 +1,205 @@
|
|||
#define Csel
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Csel")]
|
||||
public sealed class CpuTestCsel : CpuTest
|
||||
{
|
||||
#if Csel
|
||||
|
||||
[Test, Pairwise, Description("CSEL <Xd>, <Xn>, <Xm>, <cond>")]
|
||||
public void Csel_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x9A800000; // CSEL X0, X0, X0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((cond & 15) << 12);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CSEL <Wd>, <Wn>, <Wm>, <cond>")]
|
||||
public void Csel_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x1A800000; // CSEL W0, W0, W0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((cond & 15) << 12);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CSINC <Xd>, <Xn>, <Xm>, <cond>")]
|
||||
public void Csinc_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x9A800400; // CSINC X0, X0, X0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((cond & 15) << 12);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CSINC <Wd>, <Wn>, <Wm>, <cond>")]
|
||||
public void Csinc_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x1A800400; // CSINC W0, W0, W0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((cond & 15) << 12);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CSINV <Xd>, <Xn>, <Xm>, <cond>")]
|
||||
public void Csinv_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0xDA800000; // CSINV X0, X0, X0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((cond & 15) << 12);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CSINV <Wd>, <Wn>, <Wm>, <cond>")]
|
||||
public void Csinv_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x5A800000; // CSINV W0, W0, W0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((cond & 15) << 12);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CSNEG <Xd>, <Xn>, <Xm>, <cond>")]
|
||||
public void Csneg_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0xDA800400; // CSNEG X0, X0, X0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((cond & 15) << 12);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CSNEG <Wd>, <Wn>, <Wm>, <cond>")]
|
||||
public void Csneg_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
uint opcode = 0x5A800400; // CSNEG W0, W0, W0, EQ
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= ((cond & 15) << 12);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
482
src/Ryujinx.Tests/Cpu/CpuTestMisc.cs
Normal file
482
src/Ryujinx.Tests/Cpu/CpuTestMisc.cs
Normal file
|
@ -0,0 +1,482 @@
|
|||
#define Misc
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Misc")]
|
||||
public sealed class CpuTestMisc : CpuTest
|
||||
{
|
||||
#if Misc
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
{
|
||||
yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x0000000080800000ul; // -Min Normal
|
||||
yield return 0x00000000807FFFFFul; // -Max Subnormal
|
||||
yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0000000000800000ul; // +Min Normal
|
||||
yield return 0x00000000007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x0000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0x00000000FF800000ul; // -Infinity
|
||||
yield return 0x000000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (grbg << 32) | rnd1;
|
||||
yield return (grbg << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
#region "AluImm & Csel"
|
||||
[Test, Pairwise]
|
||||
public void Adds_Csinc_64bit([Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u)] uint cond) // GT, LE>
|
||||
{
|
||||
uint opCmn = 0xB100001F; // ADDS X31, X0, #0, LSL #0 -> CMN X0, #0, LSL #0
|
||||
uint opCset = 0x9A9F07E0; // CSINC X0, X31, X31, EQ -> CSET X0, NE
|
||||
|
||||
opCmn |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
opCset |= ((cond & 15) << 12);
|
||||
|
||||
SetContext(x0: xn);
|
||||
Opcode(opCmn);
|
||||
Opcode(opCset);
|
||||
Opcode(0xD65F03C0); // RET
|
||||
ExecuteOpcodes();
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Adds_Csinc_32bit([Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u)] uint cond) // GT, LE>
|
||||
{
|
||||
uint opCmn = 0x3100001F; // ADDS W31, W0, #0, LSL #0 -> CMN W0, #0, LSL #0
|
||||
uint opCset = 0x1A9F07E0; // CSINC W0, W31, W31, EQ -> CSET W0, NE
|
||||
|
||||
opCmn |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
opCset |= ((cond & 15) << 12);
|
||||
|
||||
SetContext(x0: wn);
|
||||
Opcode(opCmn);
|
||||
Opcode(opCset);
|
||||
Opcode(0xD65F03C0); // RET
|
||||
ExecuteOpcodes();
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Subs_Csinc_64bit([Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u)] uint cond) // GT, LE>
|
||||
{
|
||||
uint opCmp = 0xF100001F; // SUBS X31, X0, #0, LSL #0 -> CMP X0, #0, LSL #0
|
||||
uint opCset = 0x9A9F07E0; // CSINC X0, X31, X31, EQ -> CSET X0, NE
|
||||
|
||||
opCmp |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
opCset |= ((cond & 15) << 12);
|
||||
|
||||
SetContext(x0: xn);
|
||||
Opcode(opCmp);
|
||||
Opcode(opCset);
|
||||
Opcode(0xD65F03C0); // RET
|
||||
ExecuteOpcodes();
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Subs_Csinc_32bit([Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0u, 4095u)] uint imm,
|
||||
[Values(0b00u, 0b01u)] uint shift, // <LSL #0, LSL #12>
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u)] uint cond) // GT, LE>
|
||||
{
|
||||
uint opCmp = 0x7100001F; // SUBS W31, W0, #0, LSL #0 -> CMP W0, #0, LSL #0
|
||||
uint opCset = 0x1A9F07E0; // CSINC W0, W31, W31, EQ -> CSET W0, NE
|
||||
|
||||
opCmp |= ((shift & 3) << 22) | ((imm & 4095) << 10);
|
||||
opCset |= ((cond & 15) << 12);
|
||||
|
||||
SetContext(x0: wn);
|
||||
Opcode(opCmp);
|
||||
Opcode(opCset);
|
||||
Opcode(0xD65F03C0); // RET
|
||||
ExecuteOpcodes();
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Explicit]
|
||||
[TestCase(0xFFFFFFFDu)] // Roots.
|
||||
[TestCase(0x00000005u)]
|
||||
public void Misc1(uint a)
|
||||
{
|
||||
// ((a + 3) * (a - 5)) / ((a + 5) * (a - 3)) = 0
|
||||
|
||||
/*
|
||||
ADD W2, W0, 3
|
||||
SUB W1, W0, #5
|
||||
MUL W2, W2, W1
|
||||
ADD W1, W0, 5
|
||||
SUB W0, W0, #3
|
||||
MUL W0, W1, W0
|
||||
SDIV W0, W2, W0
|
||||
RET
|
||||
*/
|
||||
|
||||
SetContext(x0: a);
|
||||
Opcode(0x11000C02);
|
||||
Opcode(0x51001401);
|
||||
Opcode(0x1B017C42);
|
||||
Opcode(0x11001401);
|
||||
Opcode(0x51000C00);
|
||||
Opcode(0x1B007C20);
|
||||
Opcode(0x1AC00C40);
|
||||
Opcode(0xD65F03C0);
|
||||
ExecuteOpcodes();
|
||||
|
||||
Assert.That(GetContext().GetX(0), Is.Zero);
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[TestCase(-20f, -5f)] // 18 integer solutions.
|
||||
[TestCase(-12f, -6f)]
|
||||
[TestCase(-12f, 3f)]
|
||||
[TestCase( -8f, -8f)]
|
||||
[TestCase( -6f, -12f)]
|
||||
[TestCase( -5f, -20f)]
|
||||
[TestCase( -4f, 2f)]
|
||||
[TestCase( -3f, 12f)]
|
||||
[TestCase( -2f, 4f)]
|
||||
[TestCase( 2f, -4f)]
|
||||
[TestCase( 3f, -12f)]
|
||||
[TestCase( 4f, -2f)]
|
||||
[TestCase( 5f, 20f)]
|
||||
[TestCase( 6f, 12f)]
|
||||
[TestCase( 8f, 8f)]
|
||||
[TestCase( 12f, -3f)]
|
||||
[TestCase( 12f, 6f)]
|
||||
[TestCase( 20f, 5f)]
|
||||
public void Misc2(float a, float b)
|
||||
{
|
||||
// 1 / ((1 / a + 1 / b) ^ 2) = 16
|
||||
|
||||
/*
|
||||
FMOV S2, 1.0e+0
|
||||
FDIV S0, S2, S0
|
||||
FDIV S1, S2, S1
|
||||
FADD S0, S0, S1
|
||||
FDIV S0, S2, S0
|
||||
FMUL S0, S0, S0
|
||||
RET
|
||||
*/
|
||||
|
||||
SetContext(v0: MakeVectorScalar(a), v1: MakeVectorScalar(b));
|
||||
Opcode(0x1E2E1002);
|
||||
Opcode(0x1E201840);
|
||||
Opcode(0x1E211841);
|
||||
Opcode(0x1E212800);
|
||||
Opcode(0x1E201840);
|
||||
Opcode(0x1E200800);
|
||||
Opcode(0xD65F03C0);
|
||||
ExecuteOpcodes();
|
||||
|
||||
Assert.That(GetContext().GetV(0).As<float>(), Is.EqualTo(16f));
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[TestCase(-20d, -5d)] // 18 integer solutions.
|
||||
[TestCase(-12d, -6d)]
|
||||
[TestCase(-12d, 3d)]
|
||||
[TestCase( -8d, -8d)]
|
||||
[TestCase( -6d, -12d)]
|
||||
[TestCase( -5d, -20d)]
|
||||
[TestCase( -4d, 2d)]
|
||||
[TestCase( -3d, 12d)]
|
||||
[TestCase( -2d, 4d)]
|
||||
[TestCase( 2d, -4d)]
|
||||
[TestCase( 3d, -12d)]
|
||||
[TestCase( 4d, -2d)]
|
||||
[TestCase( 5d, 20d)]
|
||||
[TestCase( 6d, 12d)]
|
||||
[TestCase( 8d, 8d)]
|
||||
[TestCase( 12d, -3d)]
|
||||
[TestCase( 12d, 6d)]
|
||||
[TestCase( 20d, 5d)]
|
||||
public void Misc3(double a, double b)
|
||||
{
|
||||
// 1 / ((1 / a + 1 / b) ^ 2) = 16
|
||||
|
||||
/*
|
||||
FMOV D2, 1.0e+0
|
||||
FDIV D0, D2, D0
|
||||
FDIV D1, D2, D1
|
||||
FADD D0, D0, D1
|
||||
FDIV D0, D2, D0
|
||||
FMUL D0, D0, D0
|
||||
RET
|
||||
*/
|
||||
|
||||
SetContext(v0: MakeVectorScalar(a), v1: MakeVectorScalar(b));
|
||||
Opcode(0x1E6E1002);
|
||||
Opcode(0x1E601840);
|
||||
Opcode(0x1E611841);
|
||||
Opcode(0x1E612800);
|
||||
Opcode(0x1E601840);
|
||||
Opcode(0x1E600800);
|
||||
Opcode(0xD65F03C0);
|
||||
ExecuteOpcodes();
|
||||
|
||||
Assert.That(GetContext().GetV(0).As<double>(), Is.EqualTo(16d));
|
||||
}
|
||||
|
||||
[Test, Ignore("The Tester supports only one return point.")]
|
||||
public void MiscF([Range(0u, 92u, 1u)] uint a)
|
||||
{
|
||||
ulong Fn(uint n)
|
||||
{
|
||||
ulong x = 0, y = 1, z;
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
for (uint i = 2; i <= n; i++)
|
||||
{
|
||||
z = x + y;
|
||||
x = y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
/*
|
||||
0x0000000000001000: MOV W4, W0
|
||||
0x0000000000001004: CBZ W0, #0x34
|
||||
0x0000000000001008: CMP W0, #1
|
||||
0x000000000000100C: B.LS #0x34
|
||||
0x0000000000001010: MOVZ W2, #0x2
|
||||
0x0000000000001014: MOVZ X1, #0x1
|
||||
0x0000000000001018: MOVZ X3, #0
|
||||
0x000000000000101C: ADD X0, X3, X1
|
||||
0x0000000000001020: ADD W2, W2, #1
|
||||
0x0000000000001024: MOV X3, X1
|
||||
0x0000000000001028: MOV X1, X0
|
||||
0x000000000000102C: CMP W4, W2
|
||||
0x0000000000001030: B.HS #-0x14
|
||||
0x0000000000001034: RET
|
||||
0x0000000000001038: MOVZ X0, #0
|
||||
0x000000000000103C: RET
|
||||
0x0000000000001040: MOVZ X0, #0x1
|
||||
0x0000000000001044: RET
|
||||
*/
|
||||
|
||||
SetContext(x0: a);
|
||||
Opcode(0x2A0003E4);
|
||||
Opcode(0x340001A0);
|
||||
Opcode(0x7100041F);
|
||||
Opcode(0x540001A9);
|
||||
Opcode(0x52800042);
|
||||
Opcode(0xD2800021);
|
||||
Opcode(0xD2800003);
|
||||
Opcode(0x8B010060);
|
||||
Opcode(0x11000442);
|
||||
Opcode(0xAA0103E3);
|
||||
Opcode(0xAA0003E1);
|
||||
Opcode(0x6B02009F);
|
||||
Opcode(0x54FFFF62);
|
||||
Opcode(0xD65F03C0);
|
||||
Opcode(0xD2800000);
|
||||
Opcode(0xD65F03C0);
|
||||
Opcode(0xD2800020);
|
||||
Opcode(0xD65F03C0);
|
||||
ExecuteOpcodes();
|
||||
|
||||
Assert.That(GetContext().GetX(0), Is.EqualTo(Fn(a)));
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test]
|
||||
public void MiscR()
|
||||
{
|
||||
const ulong result = 5;
|
||||
|
||||
/*
|
||||
0x0000000000001000: MOV X0, #2
|
||||
0x0000000000001004: MOV X1, #3
|
||||
0x0000000000001008: ADD X0, X0, X1
|
||||
0x000000000000100C: RET
|
||||
*/
|
||||
|
||||
Opcode(0xD2800040);
|
||||
Opcode(0xD2800061);
|
||||
Opcode(0x8B010000);
|
||||
Opcode(0xD65F03C0);
|
||||
ExecuteOpcodes();
|
||||
|
||||
Assert.That(GetContext().GetX(0), Is.EqualTo(result));
|
||||
|
||||
Reset();
|
||||
|
||||
/*
|
||||
0x0000000000001000: MOV X0, #3
|
||||
0x0000000000001004: MOV X1, #2
|
||||
0x0000000000001008: ADD X0, X0, X1
|
||||
0x000000000000100C: RET
|
||||
*/
|
||||
|
||||
Opcode(0xD2800060);
|
||||
Opcode(0xD2800041);
|
||||
Opcode(0x8B010000);
|
||||
Opcode(0xD65F03C0);
|
||||
ExecuteOpcodes();
|
||||
|
||||
Assert.That(GetContext().GetX(0), Is.EqualTo(result));
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[TestCase( 0ul)]
|
||||
[TestCase( 1ul)]
|
||||
[TestCase( 2ul)]
|
||||
[TestCase(42ul)]
|
||||
public void SanityCheck(ulong a)
|
||||
{
|
||||
uint opcode = 0xD503201F; // NOP
|
||||
ExecutionContext context = SingleOpcode(opcode, x0: a);
|
||||
|
||||
Assert.That(context.GetX(0), Is.EqualTo(a));
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise]
|
||||
public void Misc4([ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_1S_F_))] ulong b,
|
||||
[ValueSource(nameof(_1S_F_))] ulong c,
|
||||
[Values(0ul, 1ul, 2ul, 3ul)] ulong displacement)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
Assert.Ignore();
|
||||
}
|
||||
|
||||
for (ulong gapOffset = 0; gapOffset < displacement; gapOffset++)
|
||||
{
|
||||
SetWorkingMemory(gapOffset, TestContext.CurrentContext.Random.NextByte());
|
||||
}
|
||||
|
||||
SetWorkingMemory(0x0 + displacement, BitConverter.GetBytes((uint)b));
|
||||
|
||||
SetWorkingMemory(0x4 + displacement, BitConverter.GetBytes((uint)c));
|
||||
|
||||
SetWorkingMemory(0x8 + displacement, TestContext.CurrentContext.Random.NextByte());
|
||||
SetWorkingMemory(0x9 + displacement, TestContext.CurrentContext.Random.NextByte());
|
||||
SetWorkingMemory(0xA + displacement, TestContext.CurrentContext.Random.NextByte());
|
||||
SetWorkingMemory(0xB + displacement, TestContext.CurrentContext.Random.NextByte());
|
||||
|
||||
SetContext(
|
||||
x0: DataBaseAddress + displacement,
|
||||
v0: MakeVectorE0E1(a, TestContext.CurrentContext.Random.NextULong()),
|
||||
v1: MakeVectorE0E1(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()),
|
||||
v2: MakeVectorE0E1(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()),
|
||||
overflow: TestContext.CurrentContext.Random.NextBool(),
|
||||
carry: TestContext.CurrentContext.Random.NextBool(),
|
||||
zero: TestContext.CurrentContext.Random.NextBool(),
|
||||
negative: TestContext.CurrentContext.Random.NextBool());
|
||||
|
||||
Opcode(0xBD400001); // LDR S1, [X0,#0]
|
||||
Opcode(0xBD400402); // LDR S2, [X0,#4]
|
||||
Opcode(0x1E215801); // FMIN S1, S0, S1
|
||||
Opcode(0x1E222000); // FCMP S0, S2
|
||||
Opcode(0x1E214C40); // FCSEL S0, S2, S1, MI
|
||||
Opcode(0xBD000800); // STR S0, [X0,#8]
|
||||
Opcode(0xD65F03C0); // RET
|
||||
ExecuteOpcodes();
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test]
|
||||
public void Misc5([ValueSource(nameof(_1S_F_))] ulong a)
|
||||
{
|
||||
SetContext(
|
||||
v0: MakeVectorE0E1(a, TestContext.CurrentContext.Random.NextULong()),
|
||||
v1: MakeVectorE0E1(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()),
|
||||
overflow: TestContext.CurrentContext.Random.NextBool(),
|
||||
carry: TestContext.CurrentContext.Random.NextBool(),
|
||||
zero: TestContext.CurrentContext.Random.NextBool(),
|
||||
negative: TestContext.CurrentContext.Random.NextBool());
|
||||
|
||||
Opcode(0x1E202008); // FCMP S0, #0.0
|
||||
Opcode(0x1E2E1001); // FMOV S1, #1.0
|
||||
Opcode(0x1E215800); // FMIN S0, S0, S1
|
||||
Opcode(0x1E2703E1); // FMOV S1, WZR
|
||||
Opcode(0x1E204C20); // FCSEL S0, S1, S0, MI
|
||||
Opcode(0xD65F03C0); // RET
|
||||
ExecuteOpcodes();
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
111
src/Ryujinx.Tests/Cpu/CpuTestMisc32.cs
Normal file
111
src/Ryujinx.Tests/Cpu/CpuTestMisc32.cs
Normal file
|
@ -0,0 +1,111 @@
|
|||
#define Misc32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Misc32")]
|
||||
public sealed class CpuTestMisc32 : CpuTest32
|
||||
{
|
||||
#if Misc32
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
{
|
||||
yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x0000000080800000ul; // -Min Normal
|
||||
yield return 0x00000000807FFFFFul; // -Max Subnormal
|
||||
yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0000000000800000ul; // +Min Normal
|
||||
yield return 0x00000000007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x0000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0x00000000FF800000ul; // -Infinity
|
||||
yield return 0x000000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (grbg << 32) | rnd1;
|
||||
yield return (grbg << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vmsr_Vcmp_Vmrs([ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_1S_F_))] ulong b,
|
||||
[Values] bool mode1,
|
||||
[Values] bool mode2,
|
||||
[Values] bool mode3)
|
||||
{
|
||||
V128 v4 = MakeVectorE0(a);
|
||||
V128 v5 = MakeVectorE0(b);
|
||||
|
||||
uint r0 = mode1
|
||||
? TestContext.CurrentContext.Random.NextUInt(0xf) << 28
|
||||
: TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
bool v = mode3 ? TestContext.CurrentContext.Random.NextBool() : false;
|
||||
bool c = mode3 ? TestContext.CurrentContext.Random.NextBool() : false;
|
||||
bool z = mode3 ? TestContext.CurrentContext.Random.NextBool() : false;
|
||||
bool n = mode3 ? TestContext.CurrentContext.Random.NextBool() : false;
|
||||
|
||||
int fpscr = mode1
|
||||
? (int)TestContext.CurrentContext.Random.NextUInt()
|
||||
: (int)TestContext.CurrentContext.Random.NextUInt(0xf) << 28;
|
||||
|
||||
SetContext(r0: r0, v4: v4, v5: v5, overflow: v, carry: c, zero: z, negative: n, fpscr: fpscr);
|
||||
|
||||
if (mode1)
|
||||
{
|
||||
Opcode(0xEEE10A10); // VMSR FPSCR, R0
|
||||
}
|
||||
Opcode(0xEEB48A4A); // VCMP.F32 S16, S20
|
||||
if (mode2)
|
||||
{
|
||||
Opcode(0xEEF10A10); // VMRS R0, FPSCR
|
||||
Opcode(0xE200020F); // AND R0, #0xF0000000 // R0 &= "Fpsr.Nzcv".
|
||||
}
|
||||
if (mode3)
|
||||
{
|
||||
Opcode(0xEEF1FA10); // VMRS APSR_NZCV, FPSCR
|
||||
}
|
||||
Opcode(0xE12FFF1E); // BX LR
|
||||
|
||||
ExecuteOpcodes();
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Nzcv);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
112
src/Ryujinx.Tests/Cpu/CpuTestMov.cs
Normal file
112
src/Ryujinx.Tests/Cpu/CpuTestMov.cs
Normal file
|
@ -0,0 +1,112 @@
|
|||
#define Mov
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Mov")]
|
||||
public sealed class CpuTestMov : CpuTest
|
||||
{
|
||||
#if Mov
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("MOVK <Xd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movk_64bit([Values(0u, 31u)] uint rd,
|
||||
[Random(RndCnt)] ulong xd,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u, 32u, 48u)] uint shift)
|
||||
{
|
||||
uint opcode = 0xF2800000; // MOVK X0, #0, LSL #0
|
||||
opcode |= ((rd & 31) << 0);
|
||||
opcode |= (((shift / 16) & 3) << 21) | ((imm & 65535) << 5);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x0: xd, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("MOVK <Wd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movk_32bit([Values(0u, 31u)] uint rd,
|
||||
[Random(RndCnt)] uint wd,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u)] uint shift)
|
||||
{
|
||||
uint opcode = 0x72800000; // MOVK W0, #0, LSL #0
|
||||
opcode |= ((rd & 31) << 0);
|
||||
opcode |= (((shift / 16) & 3) << 21) | ((imm & 65535) << 5);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x0: wd, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("MOVN <Xd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movn_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u, 32u, 48u)] uint shift)
|
||||
{
|
||||
uint opcode = 0x92800000; // MOVN X0, #0, LSL #0
|
||||
opcode |= ((rd & 31) << 0);
|
||||
opcode |= (((shift / 16) & 3) << 21) | ((imm & 65535) << 5);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("MOVN <Wd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movn_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u)] uint shift)
|
||||
{
|
||||
uint opcode = 0x12800000; // MOVN W0, #0, LSL #0
|
||||
opcode |= ((rd & 31) << 0);
|
||||
opcode |= (((shift / 16) & 3) << 21) | ((imm & 65535) << 5);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("MOVZ <Xd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movz_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u, 32u, 48u)] uint shift)
|
||||
{
|
||||
uint opcode = 0xD2800000; // MOVZ X0, #0, LSL #0
|
||||
opcode |= ((rd & 31) << 0);
|
||||
opcode |= (((shift / 16) & 3) << 21) | ((imm & 65535) << 5);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("MOVZ <Wd>, #<imm>{, LSL #<shift>}")]
|
||||
public void Movz_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(0u, 65535u)] uint imm,
|
||||
[Values(0u, 16u)] uint shift)
|
||||
{
|
||||
uint opcode = 0x52800000; // MOVZ W0, #0, LSL #0
|
||||
opcode |= ((rd & 31) << 0);
|
||||
opcode |= (((shift / 16) & 3) << 21) | ((imm & 65535) << 5);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
226
src/Ryujinx.Tests/Cpu/CpuTestMul.cs
Normal file
226
src/Ryujinx.Tests/Cpu/CpuTestMul.cs
Normal file
|
@ -0,0 +1,226 @@
|
|||
#define Mul
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Mul")]
|
||||
public sealed class CpuTestMul : CpuTest
|
||||
{
|
||||
#if Mul
|
||||
[Test, Pairwise, Description("MADD <Xd>, <Xn>, <Xm>, <Xa>")]
|
||||
public void Madd_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9B000000; // MADD X0, X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x3: xa, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("MADD <Wd>, <Wn>, <Wm>, <Wa>")]
|
||||
public void Madd_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wa)
|
||||
{
|
||||
uint opcode = 0x1B000000; // MADD W0, W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x3: wa, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("MSUB <Xd>, <Xn>, <Xm>, <Xa>")]
|
||||
public void Msub_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9B008000; // MSUB X0, X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x3: xa, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("MSUB <Wd>, <Wn>, <Wm>, <Wa>")]
|
||||
public void Msub_32bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wa)
|
||||
{
|
||||
uint opcode = 0x1B008000; // MSUB W0, W0, W0, W0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x3: wa, x31: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMADDL <Xd>, <Wn>, <Wm>, <Xa>")]
|
||||
public void Smaddl_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9B200000; // SMADDL X0, W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x3: xa, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UMADDL <Xd>, <Wn>, <Wm>, <Xa>")]
|
||||
public void Umaddl_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9BA00000; // UMADDL X0, W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x3: xa, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMSUBL <Xd>, <Wn>, <Wm>, <Xa>")]
|
||||
public void Smsubl_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9B208000; // SMSUBL X0, W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x3: xa, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UMSUBL <Xd>, <Wn>, <Wm>, <Xa>")]
|
||||
public void Umsubl_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(3u, 31u)] uint ra,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xa)
|
||||
{
|
||||
uint opcode = 0x9BA08000; // UMSUBL X0, W0, W0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((ra & 31) << 10) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x2: wm, x3: xa, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMULH <Xd>, <Xn>, <Xm>")]
|
||||
public void Smulh_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9B407C00; // SMULH X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UMULH <Xd>, <Xn>, <Xm>")]
|
||||
public void Umulh_64bit([Values(0u, 31u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[Values(2u, 31u)] uint rm,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xn,
|
||||
[Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] ulong xm)
|
||||
{
|
||||
uint opcode = 0x9BC07C00; // UMULH X0, X0, X0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x2: xm, x31: x31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
137
src/Ryujinx.Tests/Cpu/CpuTestMul32.cs
Normal file
137
src/Ryujinx.Tests/Cpu/CpuTestMul32.cs
Normal file
|
@ -0,0 +1,137 @@
|
|||
#define Mul32
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Mul32")]
|
||||
public sealed class CpuTestMul32 : CpuTest32
|
||||
{
|
||||
#if Mul32
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Smlabb_Smlabt_Smlatb_Smlatt_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe1000080u, // SMLABB R0, R0, R0, R0
|
||||
0xe10000C0u, // SMLABT R0, R0, R0, R0
|
||||
0xe10000A0u, // SMLATB R0, R0, R0, R0
|
||||
0xe10000E0u, // SMLATT R0, R0, R0, R0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Smlawb_Smlawt_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe1200080u, // SMLAWB R0, R0, R0, R0
|
||||
0xe12000C0u, // SMLAWT R0, R0, R0, R0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Smulbb_Smulbt_Smultb_Smultt_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe1600080u, // SMULBB R0, R0, R0
|
||||
0xe16000C0u, // SMULBT R0, R0, R0
|
||||
0xe16000A0u, // SMULTB R0, R0, R0
|
||||
0xe16000E0u, // SMULTT R0, R0, R0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Smulwb_Smulwt_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe12000a0u, // SMULWB R0, R0, R0
|
||||
0xe12000e0u, // SMULWT R0, R0, R0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Test, Pairwise, Description("SMLA<x><y> <Rd>, <Rn>, <Rm>, <Ra>")]
|
||||
public void Smla___32bit([ValueSource("_Smlabb_Smlabt_Smlatb_Smlatt_")] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rn,
|
||||
[Values(1u, 0xdu)] uint rm,
|
||||
[Values(2u, 0xdu)] uint ra,
|
||||
[Values(3u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wa)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rm & 15) << 8) | ((ra & 15) << 12) | ((rd & 15) << 16);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wn, r1: wm, r2: wa, sp: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMLAW<x> <Rd>, <Rn>, <Rm>, <Ra>")]
|
||||
public void Smlaw__32bit([ValueSource("_Smlawb_Smlawt_")] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rn,
|
||||
[Values(1u, 0xdu)] uint rm,
|
||||
[Values(2u, 0xdu)] uint ra,
|
||||
[Values(3u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wa)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rm & 15) << 8) | ((ra & 15) << 12) | ((rd & 15) << 16);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wn, r1: wm, r2: wa, sp: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMUL<x><y> <Rd>, <Rn>, <Rm>")]
|
||||
public void Smul___32bit([ValueSource("_Smulbb_Smulbt_Smultb_Smultt_")] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rn,
|
||||
[Values(1u, 0xdu)] uint rm,
|
||||
[Values(2u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rm & 15) << 8) | ((rd & 15) << 16);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wn, r1: wm, sp: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMULW<x> <Rd>, <Rn>, <Rm>")]
|
||||
public void Smulw__32bit([ValueSource("_Smulwb_Smulwt_")] uint opcode,
|
||||
[Values(0u, 0xdu)] uint rn,
|
||||
[Values(1u, 0xdu)] uint rm,
|
||||
[Values(2u, 0xdu)] uint rd,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wn,
|
||||
[Values(0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu)] uint wm)
|
||||
{
|
||||
opcode |= ((rn & 15) << 0) | ((rm & 15) << 8) | ((rd & 15) << 16);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
SingleOpcode(opcode, r0: wn, r1: wm, sp: w31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
3561
src/Ryujinx.Tests/Cpu/CpuTestSimd.cs
Normal file
3561
src/Ryujinx.Tests/Cpu/CpuTestSimd.cs
Normal file
File diff suppressed because it is too large
Load diff
325
src/Ryujinx.Tests/Cpu/CpuTestSimd32.cs
Normal file
325
src/Ryujinx.Tests/Cpu/CpuTestSimd32.cs
Normal file
|
@ -0,0 +1,325 @@
|
|||
#define Simd32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("Simd32")]
|
||||
public sealed class CpuTestSimd32 : CpuTest32
|
||||
{
|
||||
#if Simd32
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Vabs_Vneg_Vpaddl_I_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf3b10300u, // VABS.S8 D0, D0
|
||||
0xf3b10380u, // VNEG.S8 D0, D0
|
||||
0xf3b00200u // VPADDL.S8 D0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vabs_Vneg_F_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf3b90700u, // VABS.F32 D0, D0
|
||||
0xf3b90780u // VNEG.F32 D0, D0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _8B4H2S_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
{
|
||||
yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x0000000080800000ul; // -Min Normal
|
||||
yield return 0x00000000807FFFFFul; // -Max Subnormal
|
||||
yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0000000000800000ul; // +Min Normal
|
||||
yield return 0x00000000007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x0000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0x00000000FF800000ul; // -Infinity
|
||||
yield return 0x000000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (grbg << 32) | rnd1;
|
||||
yield return (grbg << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _2S_F_()
|
||||
{
|
||||
yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x8080000080800000ul; // -Min Normal
|
||||
yield return 0x807FFFFF807FFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0080000000800000ul; // +Min Normal
|
||||
yield return 0x007FFFFF007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFF800000FF800000ul; // -Infinity
|
||||
yield return 0x7F8000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (rnd1 << 32) | rnd1;
|
||||
yield return (rnd2 << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1D_F_()
|
||||
{
|
||||
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
||||
yield return 0x8010000000000000ul; // -Min Normal
|
||||
yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
|
||||
yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
|
||||
yield return 0x0010000000000000ul; // +Min Normal
|
||||
yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000000000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFFF0000000000000ul; // -Infinity
|
||||
yield return 0x7FF0000000000000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
|
||||
yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
|
||||
yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalD();
|
||||
ulong rnd2 = GenSubnormalD();
|
||||
|
||||
yield return rnd1;
|
||||
yield return rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _GenPopCnt8B_()
|
||||
{
|
||||
for (ulong cnt = 0ul; cnt <= 255ul; cnt++)
|
||||
{
|
||||
yield return (cnt << 56) | (cnt << 48) | (cnt << 40) | (cnt << 32) |
|
||||
(cnt << 24) | (cnt << 16) | (cnt << 08) | cnt;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise, Description("SHA256SU0.32 <Qd>, <Qm>")]
|
||||
public void Sha256su0_V([Values(0xF3BA03C0u)] uint opcode,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(2u)] uint rm,
|
||||
[Values(0x9BCBBF7443FB4F91ul)] ulong z0,
|
||||
[Values(0x482C58A58CBCBD59ul)] ulong z1,
|
||||
[Values(0xA0099B803625F82Aul)] ulong a0,
|
||||
[Values(0x1AA3B0B4E1AB4C8Cul)] ulong a1,
|
||||
[Values(0x29A44D72598F15F3ul)] ulong resultL,
|
||||
[Values(0x74CED221E2793F07ul)] ulong resultH)
|
||||
{
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z0, z1);
|
||||
V128 v1 = MakeVectorE0E1(a0, a1);
|
||||
|
||||
ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1, runUnicorn: false);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
|
||||
// Unicorn does not yet support hash instructions in A32.
|
||||
// CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vabs_Vneg_Vpaddl_V_I([ValueSource(nameof(_Vabs_Vneg_Vpaddl_I_))] uint opcode,
|
||||
[Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong z,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong b,
|
||||
[Values(0u, 1u, 2u)] uint size, // <S8, S16, S32>
|
||||
[Values] bool q)
|
||||
{
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
rm >>= 1; rm <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
opcode |= (size & 0x3) << 18;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
V128 v1 = MakeVectorE0E1(b, ~b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vabs_Vneg_V_F32([ValueSource(nameof(_Vabs_Vneg_F_))] uint opcode,
|
||||
[Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_2S_F_))] ulong z,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
rm >>= 1; rm <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
V128 v1 = MakeVectorE0E1(b, ~b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VCNT.8 D0, D0 | VCNT.8 Q0, Q0")]
|
||||
public void Vcnt([Values(0u, 1u)] uint rd,
|
||||
[Values(0u, 1u)] uint rm,
|
||||
[ValueSource(nameof(_GenPopCnt8B_))] ulong d0,
|
||||
[Values] bool q)
|
||||
{
|
||||
ulong d1 = ~d0; // It's expensive to have a second generator.
|
||||
|
||||
uint opcode = 0xf3b00500u; // VCNT.8 D0, D0
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1u << 6;
|
||||
|
||||
rd &= ~1u;
|
||||
rm &= ~1u;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vmovn_V([Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong z,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong b,
|
||||
[Values(0u, 1u, 2u, 3u)] uint op,
|
||||
[Values(0u, 1u, 2u)] uint size) // <S8, S16, S32>
|
||||
{
|
||||
rm >>= 1; rm <<= 1;
|
||||
|
||||
uint opcode = 0xf3b20200u; // VMOVN.S16 D0, Q0
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
opcode |= (op & 0x3) << 6;
|
||||
opcode |= (size & 0x3) << 18;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
V128 v1 = MakeVectorE0E1(b, ~b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
145
src/Ryujinx.Tests/Cpu/CpuTestSimdCrypto.cs
Normal file
145
src/Ryujinx.Tests/Cpu/CpuTestSimdCrypto.cs
Normal file
|
@ -0,0 +1,145 @@
|
|||
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
public class CpuTestSimdCrypto : CpuTest
|
||||
{
|
||||
[Test, Description("AESD <Vd>.16B, <Vn>.16B")]
|
||||
public void Aesd_V([Values(0u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[Values(0x7B5B546573745665ul)] ulong valueH,
|
||||
[Values(0x63746F725D53475Dul)] ulong valueL,
|
||||
[Random(2)] ulong roundKeyH,
|
||||
[Random(2)] ulong roundKeyL,
|
||||
[Values(0x8DCAB9BC035006BCul)] ulong resultH,
|
||||
[Values(0x8F57161E00CAFD8Dul)] ulong resultL)
|
||||
{
|
||||
uint opcode = 0x4E285800; // AESD V0.16B, V0.16B
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(roundKeyL ^ valueL, roundKeyH ^ valueH);
|
||||
V128 v1 = MakeVectorE0E1(roundKeyL, roundKeyH);
|
||||
|
||||
ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(roundKeyL));
|
||||
Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(roundKeyH));
|
||||
});
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Description("AESE <Vd>.16B, <Vn>.16B")]
|
||||
public void Aese_V([Values(0u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[Values(0x7B5B546573745665ul)] ulong valueH,
|
||||
[Values(0x63746F725D53475Dul)] ulong valueL,
|
||||
[Random(2)] ulong roundKeyH,
|
||||
[Random(2)] ulong roundKeyL,
|
||||
[Values(0x8F92A04DFBED204Dul)] ulong resultH,
|
||||
[Values(0x4C39B1402192A84Cul)] ulong resultL)
|
||||
{
|
||||
uint opcode = 0x4E284800; // AESE V0.16B, V0.16B
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(roundKeyL ^ valueL, roundKeyH ^ valueH);
|
||||
V128 v1 = MakeVectorE0E1(roundKeyL, roundKeyH);
|
||||
|
||||
ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(roundKeyL));
|
||||
Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(roundKeyH));
|
||||
});
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Description("AESIMC <Vd>.16B, <Vn>.16B")]
|
||||
public void Aesimc_V([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(0x8DCAB9DC035006BCul)] ulong valueH,
|
||||
[Values(0x8F57161E00CAFD8Dul)] ulong valueL,
|
||||
[Values(0xD635A667928B5EAEul)] ulong resultH,
|
||||
[Values(0xEEC9CC3BC55F5777ul)] ulong resultL)
|
||||
{
|
||||
uint opcode = 0x4E287800; // AESIMC V0.16B, V0.16B
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
V128 v = MakeVectorE0E1(valueL, valueH);
|
||||
|
||||
ExecutionContext context = SingleOpcode(
|
||||
opcode,
|
||||
v0: rn == 0u ? v : default(V128),
|
||||
v1: rn == 1u ? v : default(V128));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
if (rn == 1u)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(valueL));
|
||||
Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(valueH));
|
||||
});
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Description("AESMC <Vd>.16B, <Vn>.16B")]
|
||||
public void Aesmc_V([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(0x627A6F6644B109C8ul)] ulong valueH,
|
||||
[Values(0x2B18330A81C3B3E5ul)] ulong valueL,
|
||||
[Values(0x7B5B546573745665ul)] ulong resultH,
|
||||
[Values(0x63746F725D53475Dul)] ulong resultL)
|
||||
{
|
||||
uint opcode = 0x4E286800; // AESMC V0.16B, V0.16B
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
V128 v = MakeVectorE0E1(valueL, valueH);
|
||||
|
||||
ExecutionContext context = SingleOpcode(
|
||||
opcode,
|
||||
v0: rn == 0u ? v : default(V128),
|
||||
v1: rn == 1u ? v : default(V128));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
if (rn == 1u)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(valueL));
|
||||
Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(valueH));
|
||||
});
|
||||
}
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
}
|
||||
}
|
155
src/Ryujinx.Tests/Cpu/CpuTestSimdCrypto32.cs
Normal file
155
src/Ryujinx.Tests/Cpu/CpuTestSimdCrypto32.cs
Normal file
|
@ -0,0 +1,155 @@
|
|||
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
public class CpuTestSimdCrypto32 : CpuTest32
|
||||
{
|
||||
[Test, Description("AESD.8 <Qd>, <Qm>")]
|
||||
public void Aesd_V([Values(0u)] uint rd,
|
||||
[Values(2u)] uint rm,
|
||||
[Values(0x7B5B546573745665ul)] ulong valueH,
|
||||
[Values(0x63746F725D53475Dul)] ulong valueL,
|
||||
[Random(2)] ulong roundKeyH,
|
||||
[Random(2)] ulong roundKeyL,
|
||||
[Values(0x8DCAB9BC035006BCul)] ulong resultH,
|
||||
[Values(0x8F57161E00CAFD8Dul)] ulong resultL)
|
||||
{
|
||||
uint opcode = 0xf3b00340; // AESD.8 Q0, Q0
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(roundKeyL ^ valueL, roundKeyH ^ valueH);
|
||||
V128 v1 = MakeVectorE0E1(roundKeyL, roundKeyH);
|
||||
|
||||
ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1, runUnicorn: false);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(roundKeyL));
|
||||
Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(roundKeyH));
|
||||
});
|
||||
|
||||
// Unicorn does not yet support crypto instructions in A32.
|
||||
// CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Description("AESE.8 <Qd>, <Qm>")]
|
||||
public void Aese_V([Values(0u)] uint rd,
|
||||
[Values(2u)] uint rm,
|
||||
[Values(0x7B5B546573745665ul)] ulong valueH,
|
||||
[Values(0x63746F725D53475Dul)] ulong valueL,
|
||||
[Random(2)] ulong roundKeyH,
|
||||
[Random(2)] ulong roundKeyL,
|
||||
[Values(0x8F92A04DFBED204Dul)] ulong resultH,
|
||||
[Values(0x4C39B1402192A84Cul)] ulong resultL)
|
||||
{
|
||||
uint opcode = 0xf3b00300; // AESE.8 Q0, Q0
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(roundKeyL ^ valueL, roundKeyH ^ valueH);
|
||||
V128 v1 = MakeVectorE0E1(roundKeyL, roundKeyH);
|
||||
|
||||
ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1, runUnicorn: false);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(roundKeyL));
|
||||
Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(roundKeyH));
|
||||
});
|
||||
|
||||
// Unicorn does not yet support crypto instructions in A32.
|
||||
// CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Description("AESIMC.8 <Qd>, <Qm>")]
|
||||
public void Aesimc_V([Values(0u)] uint rd,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0x8DCAB9DC035006BCul)] ulong valueH,
|
||||
[Values(0x8F57161E00CAFD8Dul)] ulong valueL,
|
||||
[Values(0xD635A667928B5EAEul)] ulong resultH,
|
||||
[Values(0xEEC9CC3BC55F5777ul)] ulong resultL)
|
||||
{
|
||||
uint opcode = 0xf3b003c0; // AESIMC.8 Q0, Q0
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
|
||||
V128 v = MakeVectorE0E1(valueL, valueH);
|
||||
|
||||
ExecutionContext context = SingleOpcode(
|
||||
opcode,
|
||||
v0: rm == 0u ? v : default(V128),
|
||||
v1: rm == 2u ? v : default(V128),
|
||||
runUnicorn: false);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
if (rm == 2u)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(valueL));
|
||||
Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(valueH));
|
||||
});
|
||||
}
|
||||
|
||||
// Unicorn does not yet support crypto instructions in A32.
|
||||
// CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Description("AESMC.8 <Qd>, <Qm>")]
|
||||
public void Aesmc_V([Values(0u)] uint rd,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0x627A6F6644B109C8ul)] ulong valueH,
|
||||
[Values(0x2B18330A81C3B3E5ul)] ulong valueL,
|
||||
[Values(0x7B5B546573745665ul)] ulong resultH,
|
||||
[Values(0x63746F725D53475Dul)] ulong resultL)
|
||||
{
|
||||
uint opcode = 0xf3b00380; // AESMC.8 Q0, Q0
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
|
||||
V128 v = MakeVectorE0E1(valueL, valueH);
|
||||
|
||||
ExecutionContext context = SingleOpcode(
|
||||
opcode,
|
||||
v0: rm == 0u ? v : default(V128),
|
||||
v1: rm == 2u ? v : default(V128),
|
||||
runUnicorn: false);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
if (rm == 2u)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(valueL));
|
||||
Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(valueH));
|
||||
});
|
||||
}
|
||||
|
||||
// Unicorn does not yet support crypto instructions in A32.
|
||||
// CompareAgainstUnicorn();
|
||||
}
|
||||
}
|
||||
}
|
674
src/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs
Normal file
674
src/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs
Normal file
|
@ -0,0 +1,674 @@
|
|||
#define SimdCvt
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdCvt")]
|
||||
public sealed class CpuTestSimdCvt : CpuTest
|
||||
{
|
||||
#if SimdCvt
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static uint[] _W_()
|
||||
{
|
||||
return new[] { 0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu };
|
||||
}
|
||||
|
||||
private static ulong[] _X_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1S_F_WX_()
|
||||
{
|
||||
// int
|
||||
yield return 0x00000000CF000001ul; // -2.1474839E9f (-2147483904)
|
||||
yield return 0x00000000CF000000ul; // -2.14748365E9f (-2147483648)
|
||||
yield return 0x00000000CEFFFFFFul; // -2.14748352E9f (-2147483520)
|
||||
yield return 0x000000004F000001ul; // 2.1474839E9f (2147483904)
|
||||
yield return 0x000000004F000000ul; // 2.14748365E9f (2147483648)
|
||||
yield return 0x000000004EFFFFFFul; // 2.14748352E9f (2147483520)
|
||||
|
||||
// long
|
||||
yield return 0x00000000DF000001ul; // -9.223373E18f (-9223373136366403584)
|
||||
yield return 0x00000000DF000000ul; // -9.223372E18f (-9223372036854775808)
|
||||
yield return 0x00000000DEFFFFFFul; // -9.2233715E18f (-9223371487098961920)
|
||||
yield return 0x000000005F000001ul; // 9.223373E18f (9223373136366403584)
|
||||
yield return 0x000000005F000000ul; // 9.223372E18f (9223372036854775808)
|
||||
yield return 0x000000005EFFFFFFul; // 9.2233715E18f (9223371487098961920)
|
||||
|
||||
// uint
|
||||
yield return 0x000000004F800001ul; // 4.2949678E9f (4294967808)
|
||||
yield return 0x000000004F800000ul; // 4.2949673E9f (4294967296)
|
||||
yield return 0x000000004F7FFFFFul; // 4.29496704E9f (4294967040)
|
||||
|
||||
// ulong
|
||||
yield return 0x000000005F800001ul; // 1.8446746E19f (18446746272732807168)
|
||||
yield return 0x000000005F800000ul; // 1.8446744E19f (18446744073709551616)
|
||||
yield return 0x000000005F7FFFFFul; // 1.8446743E19f (18446742974197923840)
|
||||
|
||||
yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x0000000080800000ul; // -Min Normal
|
||||
yield return 0x00000000807FFFFFul; // -Max Subnormal
|
||||
yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0000000000800000ul; // +Min Normal
|
||||
yield return 0x00000000007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x0000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0x00000000FF800000ul; // -Infinity
|
||||
yield return 0x000000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
ulong rnd1 = (uint)BitConverter.SingleToInt32Bits(
|
||||
(int)TestContext.CurrentContext.Random.NextUInt());
|
||||
ulong rnd2 = (uint)BitConverter.SingleToInt32Bits(
|
||||
(long)TestContext.CurrentContext.Random.NextULong());
|
||||
ulong rnd3 = (uint)BitConverter.SingleToInt32Bits(
|
||||
TestContext.CurrentContext.Random.NextUInt());
|
||||
ulong rnd4 = (uint)BitConverter.SingleToInt32Bits(
|
||||
TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
ulong rnd5 = GenNormalS();
|
||||
ulong rnd6 = GenSubnormalS();
|
||||
|
||||
yield return (grbg << 32) | rnd1;
|
||||
yield return (grbg << 32) | rnd2;
|
||||
yield return (grbg << 32) | rnd3;
|
||||
yield return (grbg << 32) | rnd4;
|
||||
|
||||
yield return (grbg << 32) | rnd5;
|
||||
yield return (grbg << 32) | rnd6;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1D_F_WX_()
|
||||
{
|
||||
// int
|
||||
yield return 0xC1E0000000200000ul; // -2147483649.0000000d (-2147483649)
|
||||
yield return 0xC1E0000000000000ul; // -2147483648.0000000d (-2147483648)
|
||||
yield return 0xC1DFFFFFFFC00000ul; // -2147483647.0000000d (-2147483647)
|
||||
yield return 0x41E0000000200000ul; // 2147483649.0000000d (2147483649)
|
||||
yield return 0x41E0000000000000ul; // 2147483648.0000000d (2147483648)
|
||||
yield return 0x41DFFFFFFFC00000ul; // 2147483647.0000000d (2147483647)
|
||||
|
||||
// long
|
||||
yield return 0xC3E0000000000001ul; // -9.2233720368547780E18d (-9223372036854778000)
|
||||
yield return 0xC3E0000000000000ul; // -9.2233720368547760E18d (-9223372036854776000)
|
||||
yield return 0xC3DFFFFFFFFFFFFFul; // -9.2233720368547750E18d (-9223372036854775000)
|
||||
yield return 0x43E0000000000001ul; // 9.2233720368547780E18d (9223372036854778000)
|
||||
yield return 0x43E0000000000000ul; // 9.2233720368547760E18d (9223372036854776000)
|
||||
yield return 0x43DFFFFFFFFFFFFFul; // 9.2233720368547750E18d (9223372036854775000)
|
||||
|
||||
// uint
|
||||
yield return 0x41F0000000100000ul; // 4294967297.0000000d (4294967297)
|
||||
yield return 0x41F0000000000000ul; // 4294967296.0000000d (4294967296)
|
||||
yield return 0x41EFFFFFFFE00000ul; // 4294967295.0000000d (4294967295)
|
||||
|
||||
// ulong
|
||||
yield return 0x43F0000000000001ul; // 1.8446744073709556e19d (18446744073709556000)
|
||||
yield return 0x43F0000000000000ul; // 1.8446744073709552E19d (18446744073709552000)
|
||||
yield return 0x43EFFFFFFFFFFFFFul; // 1.8446744073709550e19d (18446744073709550000)
|
||||
|
||||
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
||||
yield return 0x8010000000000000ul; // -Min Normal
|
||||
yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
|
||||
yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
|
||||
yield return 0x0010000000000000ul; // +Min Normal
|
||||
yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000000000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFFF0000000000000ul; // -Infinity
|
||||
yield return 0x7FF0000000000000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
|
||||
yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
|
||||
yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = (ulong)BitConverter.DoubleToInt64Bits(
|
||||
(int)TestContext.CurrentContext.Random.NextUInt());
|
||||
ulong rnd2 = (ulong)BitConverter.DoubleToInt64Bits(
|
||||
(long)TestContext.CurrentContext.Random.NextULong());
|
||||
ulong rnd3 = (ulong)BitConverter.DoubleToInt64Bits(
|
||||
TestContext.CurrentContext.Random.NextUInt());
|
||||
ulong rnd4 = (ulong)BitConverter.DoubleToInt64Bits(
|
||||
TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
ulong rnd5 = GenNormalD();
|
||||
ulong rnd6 = GenSubnormalD();
|
||||
|
||||
yield return rnd1;
|
||||
yield return rnd2;
|
||||
yield return rnd3;
|
||||
yield return rnd4;
|
||||
|
||||
yield return rnd5;
|
||||
yield return rnd6;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _F_Cvt_AMPZ_SU_Gp_SW_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E240000u, // FCVTAS W0, S0
|
||||
0x1E250000u, // FCVTAU W0, S0
|
||||
0x1E300000u, // FCVTMS W0, S0
|
||||
0x1E310000u, // FCVTMU W0, S0
|
||||
0x1E200000u, // FCVTNS W0, S0
|
||||
0x1E280000u, // FCVTPS W0, S0
|
||||
0x1E290000u, // FCVTPU W0, S0
|
||||
0x1E380000u, // FCVTZS W0, S0
|
||||
0x1E390000u // FCVTZU W0, S0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cvt_AMPZ_SU_Gp_SX_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x9E240000u, // FCVTAS X0, S0
|
||||
0x9E250000u, // FCVTAU X0, S0
|
||||
0x9E300000u, // FCVTMS X0, S0
|
||||
0x9E310000u, // FCVTMU X0, S0
|
||||
0x9E200000u, // FCVTNS X0, S0
|
||||
0x9E280000u, // FCVTPS X0, S0
|
||||
0x9E290000u, // FCVTPU X0, S0
|
||||
0x9E380000u, // FCVTZS X0, S0
|
||||
0x9E390000u // FCVTZU X0, S0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cvt_AMPZ_SU_Gp_DW_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E640000u, // FCVTAS W0, D0
|
||||
0x1E650000u, // FCVTAU W0, D0
|
||||
0x1E700000u, // FCVTMS W0, D0
|
||||
0x1E710000u, // FCVTMU W0, D0
|
||||
0x1E600000u, // FCVTNS W0, D0
|
||||
0x1E680000u, // FCVTPS W0, D0
|
||||
0x1E690000u, // FCVTPU W0, D0
|
||||
0x1E780000u, // FCVTZS W0, D0
|
||||
0x1E790000u // FCVTZU W0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cvt_AMPZ_SU_Gp_DX_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x9E640000u, // FCVTAS X0, D0
|
||||
0x9E650000u, // FCVTAU X0, D0
|
||||
0x9E700000u, // FCVTMS X0, D0
|
||||
0x9E710000u, // FCVTMU X0, D0
|
||||
0x9E600000u, // FCVTNS X0, D0
|
||||
0x9E680000u, // FCVTPS X0, D0
|
||||
0x9E690000u, // FCVTPU X0, D0
|
||||
0x9E780000u, // FCVTZS X0, D0
|
||||
0x9E790000u // FCVTZU X0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cvt_Z_SU_Gp_Fixed_SW_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E188000u, // FCVTZS W0, S0, #32
|
||||
0x1E198000u // FCVTZU W0, S0, #32
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cvt_Z_SU_Gp_Fixed_SX_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x9E180000u, // FCVTZS X0, S0, #64
|
||||
0x9E190000u // FCVTZU X0, S0, #64
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cvt_Z_SU_Gp_Fixed_DW_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E588000u, // FCVTZS W0, D0, #32
|
||||
0x1E598000u // FCVTZU W0, D0, #32
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Cvt_Z_SU_Gp_Fixed_DX_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x9E580000u, // FCVTZS X0, D0, #64
|
||||
0x9E590000u // FCVTZU X0, D0, #64
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_WS_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E220000u, // SCVTF S0, W0
|
||||
0x1E230000u // UCVTF S0, W0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_WD_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E620000u, // SCVTF D0, W0
|
||||
0x1E630000u // UCVTF D0, W0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_XS_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x9E220000u, // SCVTF S0, X0
|
||||
0x9E230000u // UCVTF S0, X0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_XD_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x9E620000u, // SCVTF D0, X0
|
||||
0x9E630000u // UCVTF D0, X0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_Fixed_WS_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E028000u, // SCVTF S0, W0, #32
|
||||
0x1E038000u // UCVTF S0, W0, #32
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_Fixed_WD_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E428000u, // SCVTF D0, W0, #32
|
||||
0x1E438000u // UCVTF D0, W0, #32
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_Fixed_XS_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x9E020000u, // SCVTF S0, X0, #64
|
||||
0x9E030000u // UCVTF S0, X0, #64
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Cvt_F_Gp_Fixed_XD_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x9E420000u, // SCVTF D0, X0, #64
|
||||
0x9E430000u // UCVTF D0, X0, #64
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_AMPZ_SU_Gp_SW([ValueSource(nameof(_F_Cvt_AMPZ_SU_Gp_SW_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_1S_F_WX_))] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32;
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_AMPZ_SU_Gp_SX([ValueSource(nameof(_F_Cvt_AMPZ_SU_Gp_SX_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_1S_F_WX_))] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, x31: x31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_AMPZ_SU_Gp_DW([ValueSource(nameof(_F_Cvt_AMPZ_SU_Gp_DW_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_1D_F_WX_))] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32;
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_AMPZ_SU_Gp_DX([ValueSource(nameof(_F_Cvt_AMPZ_SU_Gp_DX_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_1D_F_WX_))] ulong a)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, x31: x31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_SW([ValueSource(nameof(_F_Cvt_Z_SU_Gp_Fixed_SW_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_1S_F_WX_))] ulong a,
|
||||
[Values(1u, 32u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (scale << 10);
|
||||
|
||||
ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32;
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_SX([ValueSource(nameof(_F_Cvt_Z_SU_Gp_Fixed_SX_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_1S_F_WX_))] ulong a,
|
||||
[Values(1u, 64u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (scale << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, x31: x31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_DW([ValueSource(nameof(_F_Cvt_Z_SU_Gp_Fixed_DW_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_1D_F_WX_))] ulong a,
|
||||
[Values(1u, 32u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (scale << 10);
|
||||
|
||||
ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32;
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Cvt_Z_SU_Gp_Fixed_DX([ValueSource(nameof(_F_Cvt_Z_SU_Gp_Fixed_DX_))] uint opcodes,
|
||||
[Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_1D_F_WX_))] ulong a,
|
||||
[Values(1u, 64u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (scale << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
|
||||
SingleOpcode(opcodes, x31: x31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_WS([ValueSource(nameof(_SU_Cvt_F_Gp_WS_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_W_))] uint wn)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_WD([ValueSource(nameof(_SU_Cvt_F_Gp_WD_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_W_))] uint wn)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(z);
|
||||
|
||||
SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_XS([ValueSource(nameof(_SU_Cvt_F_Gp_XS_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_X_))] ulong xn)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_XD([ValueSource(nameof(_SU_Cvt_F_Gp_XD_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_X_))] ulong xn)
|
||||
{
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(z);
|
||||
|
||||
SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_Fixed_WS([ValueSource(nameof(_SU_Cvt_F_Gp_Fixed_WS_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(1u, 32u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (scale << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_Fixed_WD([ValueSource(nameof(_SU_Cvt_F_Gp_Fixed_WD_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(1u, 32u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (scale << 10);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(z);
|
||||
|
||||
SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_Fixed_XS([ValueSource(nameof(_SU_Cvt_F_Gp_Fixed_XS_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_X_))] ulong xn,
|
||||
[Values(1u, 64u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (scale << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void SU_Cvt_F_Gp_Fixed_XD([ValueSource(nameof(_SU_Cvt_F_Gp_Fixed_XD_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_X_))] ulong xn,
|
||||
[Values(1u, 64u)] uint fBits)
|
||||
{
|
||||
uint scale = (64u - fBits) & 0x3Fu;
|
||||
|
||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (scale << 10);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(z);
|
||||
|
||||
SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
431
src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs
Normal file
431
src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs
Normal file
|
@ -0,0 +1,431 @@
|
|||
#define SimdCvt32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdCvt32")]
|
||||
public sealed class CpuTestSimdCvt32 : CpuTest32
|
||||
{
|
||||
#if SimdCvt32
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Vrint_AMNP_V_F32_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf3ba0500u, // VRINTA.F32 Q0, Q0
|
||||
0xf3ba0680u, // VRINTM.F32 Q0, Q0
|
||||
0xf3ba0400u, // VRINTN.F32 Q0, Q0
|
||||
0xf3ba0780u // VRINTP.F32 Q0, Q0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static uint[] _1S_()
|
||||
{
|
||||
return new[] { 0x00000000u, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu };
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
{
|
||||
yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x0000000080800000ul; // -Min Normal
|
||||
yield return 0x00000000807FFFFFul; // -Max Subnormal
|
||||
yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0000000000800000ul; // +Min Normal
|
||||
yield return 0x00000000007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x0000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0x00000000FF800000ul; // -Infinity
|
||||
yield return 0x000000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (grbg << 32) | rnd1;
|
||||
yield return (grbg << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _2S_F_()
|
||||
{
|
||||
yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x8080000080800000ul; // -Min Normal
|
||||
yield return 0x807FFFFF807FFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0080000000800000ul; // +Min Normal
|
||||
yield return 0x007FFFFF007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFF800000FF800000ul; // -Infinity
|
||||
yield return 0x7F8000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (rnd1 << 32) | rnd1;
|
||||
yield return (rnd2 << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1D_F_()
|
||||
{
|
||||
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
||||
yield return 0x8010000000000000ul; // -Min Normal
|
||||
yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
|
||||
yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
|
||||
yield return 0x0010000000000000ul; // +Min Normal
|
||||
yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000000000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFFF0000000000000ul; // -Infinity
|
||||
yield return 0x7FF0000000000000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
|
||||
yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
|
||||
yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalD();
|
||||
ulong rnd2 = GenSubnormalD();
|
||||
|
||||
yield return rnd1;
|
||||
yield return rnd2;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise, Description("VCVT.<dt>.F32 <Sd>, <Sm>")]
|
||||
public void Vcvt_F32_I32([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s0,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s1,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s2,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s3,
|
||||
[Values] bool unsigned) // <U32, S32>
|
||||
{
|
||||
uint opcode = 0xeebc0ac0u; // VCVT.U32.F32 S0, S0
|
||||
|
||||
if (!unsigned)
|
||||
{
|
||||
opcode |= 1 << 16; // opc2<0>
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||
|
||||
V128 v0 = MakeVectorE0E1E2E3((uint)s0, (uint)s1, (uint)s2, (uint)s3);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise, Description("VCVT.<dt>.F64 <Sd>, <Dm>")]
|
||||
public void Vcvt_F64_I32([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u)] uint rm,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d0,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d1,
|
||||
[Values] bool unsigned) // <U32, S32>
|
||||
{
|
||||
uint opcode = 0xeebc0bc0u; // VCVT.U32.F64 S0, D0
|
||||
|
||||
if (!unsigned)
|
||||
{
|
||||
opcode |= 1 << 16; // opc2<0>
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise, Description("VCVT.F32.<dt> <Sd>, <Sm>")]
|
||||
public void Vcvt_I32_F32([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1S_))] uint s0,
|
||||
[ValueSource(nameof(_1S_))] uint s1,
|
||||
[ValueSource(nameof(_1S_))] uint s2,
|
||||
[ValueSource(nameof(_1S_))] uint s3,
|
||||
[Values] bool unsigned, // <U32, S32>
|
||||
[Values(RMode.Rn)] RMode rMode)
|
||||
{
|
||||
uint opcode = 0xeeb80a40u; // VCVT.F32.U32 S0, S0
|
||||
|
||||
if (!unsigned)
|
||||
{
|
||||
opcode |= 1 << 7; // op
|
||||
}
|
||||
|
||||
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||
|
||||
V128 v0 = MakeVectorE0E1E2E3(s0, s1, s2, s3);
|
||||
|
||||
int fpscr = (int)rMode << (int)Fpcr.RMode;
|
||||
|
||||
SingleOpcode(opcode, v0: v0, fpscr: fpscr);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise, Description("VCVT.F64.<dt> <Dd>, <Sm>")]
|
||||
public void Vcvt_I32_F64([Values(0u, 1u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1S_))] uint s0,
|
||||
[ValueSource(nameof(_1S_))] uint s1,
|
||||
[ValueSource(nameof(_1S_))] uint s2,
|
||||
[ValueSource(nameof(_1S_))] uint s3,
|
||||
[Values] bool unsigned, // <U32, S32>
|
||||
[Values(RMode.Rn)] RMode rMode)
|
||||
{
|
||||
uint opcode = 0xeeb80b40u; // VCVT.F64.U32 D0, S0
|
||||
|
||||
if (!unsigned)
|
||||
{
|
||||
opcode |= 1 << 7; // op
|
||||
}
|
||||
|
||||
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
|
||||
V128 v0 = MakeVectorE0E1E2E3(s0, s1, s2, s3);
|
||||
|
||||
int fpscr = (int)rMode << (int)Fpcr.RMode;
|
||||
|
||||
SingleOpcode(opcode, v0: v0, fpscr: fpscr);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void Vrint_AMNP_V_F32([ValueSource(nameof(_Vrint_AMNP_V_F32_))] uint opcode,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_2S_F_))] ulong d0,
|
||||
[ValueSource(nameof(_2S_F_))] ulong d1,
|
||||
[ValueSource(nameof(_2S_F_))] ulong d2,
|
||||
[ValueSource(nameof(_2S_F_))] ulong d3,
|
||||
[Values] bool q)
|
||||
{
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
rm >>= 1; rm <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||
V128 v1 = MakeVectorE0E1(d2, d3);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VRINTX.F<size> <Sd>, <Sm>")]
|
||||
public void Vrintx_S([Values(0u, 1u)] uint rd,
|
||||
[Values(0u, 1u)] uint rm,
|
||||
[Values(2u, 3u)] uint size,
|
||||
[ValueSource(nameof(_1D_F_))] ulong s0,
|
||||
[ValueSource(nameof(_1D_F_))] ulong s1,
|
||||
[ValueSource(nameof(_1D_F_))] ulong s2,
|
||||
[Values(RMode.Rn, RMode.Rm, RMode.Rp)] RMode rMode)
|
||||
{
|
||||
uint opcode = 0xEB70A40;
|
||||
V128 v0, v1, v2;
|
||||
if (size == 2)
|
||||
{
|
||||
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||
opcode |= ((rd & 0x1e) >> 11) | ((rm & 0x1) << 22);
|
||||
v0 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s0), (uint)BitConverter.SingleToInt32Bits(s0));
|
||||
v1 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s1), (uint)BitConverter.SingleToInt32Bits(s0));
|
||||
v2 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s2), (uint)BitConverter.SingleToInt32Bits(s1));
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode |= ((rm & 0xf) << 0) | ((rd & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
v0 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s0), (uint)BitConverter.DoubleToInt64Bits(s0));
|
||||
v1 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s1), (uint)BitConverter.DoubleToInt64Bits(s0));
|
||||
v2 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s2), (uint)BitConverter.DoubleToInt64Bits(s1));
|
||||
}
|
||||
|
||||
opcode |= ((size & 3) << 8);
|
||||
|
||||
int fpscr = (int)rMode << (int)Fpcr.RMode;
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise, Description("VCVT<top>.F16.F32 <Sd>, <Dm>")]
|
||||
public void Vcvt_F32_F16([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1S_))] uint s0,
|
||||
[ValueSource(nameof(_1S_))] uint s1,
|
||||
[ValueSource(nameof(_1S_))] uint s2,
|
||||
[ValueSource(nameof(_1S_))] uint s3,
|
||||
[Values] bool top)
|
||||
{
|
||||
uint opcode = 0xeeb30a40; // VCVTB.F16.F32 S0, D0
|
||||
|
||||
if (top)
|
||||
{
|
||||
opcode |= 1 << 7;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||
|
||||
V128 v0 = MakeVectorE0E1E2E3(s0, s1, s2, s3);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise, Description("VCVT<top>.F16.F64 <Sd>, <Dm>")]
|
||||
public void Vcvt_F64_F16([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u)] uint rm,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d0,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d1,
|
||||
[Values] bool top)
|
||||
{
|
||||
uint opcode = 0xeeb30b40; // VCVTB.F16.F64 S0, D0
|
||||
|
||||
if (top)
|
||||
{
|
||||
opcode |= 1 << 7;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise, Description("VCVT<top>.F<size>.F16 <Vd>, <Sm>")]
|
||||
public void Vcvt_F16_Fx([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d0,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d1,
|
||||
[Values] bool top,
|
||||
[Values] bool sz)
|
||||
{
|
||||
uint opcode = 0xeeb20a40; // VCVTB.F32.F16 S0, S0
|
||||
|
||||
if (top)
|
||||
{
|
||||
opcode |= 1 << 7;
|
||||
}
|
||||
|
||||
if (sz)
|
||||
{
|
||||
opcode |= 1 << 8;
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||
}
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
70
src/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs
Normal file
70
src/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
#define SimdExt
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdExt")]
|
||||
public sealed class CpuTestSimdExt : CpuTest
|
||||
{
|
||||
#if SimdExt
|
||||
|
||||
#region "ValueSource"
|
||||
private static ulong[] _8B_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Test, Pairwise, Description("EXT <Vd>.8B, <Vn>.8B, <Vm>.8B, #<index>")]
|
||||
public void Ext_V_8B([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[ValueSource(nameof(_8B_))] ulong b,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
uint imm4 = index & 0x7u;
|
||||
|
||||
uint opcode = 0x2E000000; // EXT V0.8B, V0.8B, V0.8B, #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm4 << 11);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0(b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("EXT <Vd>.16B, <Vn>.16B, <Vm>.16B, #<index>")]
|
||||
public void Ext_V_16B([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[ValueSource(nameof(_8B_))] ulong b,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
uint imm4 = index & 0xFu;
|
||||
|
||||
uint opcode = 0x6E000000; // EXT V0.16B, V0.16B, V0.16B, #0
|
||||
opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm4 << 11);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
V128 v2 = MakeVectorE0E1(b, b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
235
src/Ryujinx.Tests/Cpu/CpuTestSimdFcond.cs
Normal file
235
src/Ryujinx.Tests/Cpu/CpuTestSimdFcond.cs
Normal file
|
@ -0,0 +1,235 @@
|
|||
#define SimdFcond
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdFcond")]
|
||||
public sealed class CpuTestSimdFcond : CpuTest
|
||||
{
|
||||
#if SimdFcond
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
{
|
||||
yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x0000000080800000ul; // -Min Normal
|
||||
yield return 0x00000000807FFFFFul; // -Max Subnormal
|
||||
yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0000000000800000ul; // +Min Normal
|
||||
yield return 0x00000000007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x0000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0x00000000FF800000ul; // -Infinity
|
||||
yield return 0x000000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (grbg << 32) | rnd1;
|
||||
yield return (grbg << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1D_F_()
|
||||
{
|
||||
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
||||
yield return 0x8010000000000000ul; // -Min Normal
|
||||
yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
|
||||
yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
|
||||
yield return 0x0010000000000000ul; // +Min Normal
|
||||
yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000000000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFFF0000000000000ul; // -Infinity
|
||||
yield return 0x7FF0000000000000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
|
||||
yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
|
||||
yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalD();
|
||||
ulong rnd2 = GenSubnormalD();
|
||||
|
||||
yield return rnd1;
|
||||
yield return rnd2;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _F_Ccmp_Ccmpe_S_S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E220420u, // FCCMP S1, S2, #0, EQ
|
||||
0x1E220430u // FCCMPE S1, S2, #0, EQ
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Ccmp_Ccmpe_S_D_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E620420u, // FCCMP D1, D2, #0, EQ
|
||||
0x1E620430u // FCCMPE D1, D2, #0, EQ
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Csel_S_S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E220C20u // FCSEL S0, S1, S2, EQ
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Csel_S_D_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E620C20u // FCSEL D0, D1, D2, EQ
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntNzcv = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Ccmp_Ccmpe_S_S([ValueSource(nameof(_F_Ccmp_Ccmpe_S_S_))] uint opcodes,
|
||||
[ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_1S_F_))] ulong b,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
opcodes |= ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0(b);
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
SingleOpcode(opcodes, v1: v1, v2: v2, overflow: v, carry: c, zero: z, negative: n);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Ccmp_Ccmpe_S_D([ValueSource(nameof(_F_Ccmp_Ccmpe_S_D_))] uint opcodes,
|
||||
[ValueSource(nameof(_1D_F_))] ulong a,
|
||||
[ValueSource(nameof(_1D_F_))] ulong b,
|
||||
[Random(0u, 15u, RndCntNzcv)] uint nzcv,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
opcodes |= ((cond & 15) << 12) | ((nzcv & 15) << 0);
|
||||
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0(b);
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
SingleOpcode(opcodes, v1: v1, v2: v2, overflow: v, carry: c, zero: z, negative: n);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Csel_S_S([ValueSource(nameof(_F_Csel_S_S_))] uint opcodes,
|
||||
[ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_1S_F_))] ulong b,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
opcodes |= ((cond & 15) << 12);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0(b);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Csel_S_D([ValueSource(nameof(_F_Csel_S_D_))] uint opcodes,
|
||||
[ValueSource(nameof(_1D_F_))] ulong a,
|
||||
[ValueSource(nameof(_1D_F_))] ulong b,
|
||||
[Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // <EQ, NE, CS/HS, CC/LO,
|
||||
0b0100u, 0b0101u, 0b0110u, 0b0111u, // MI, PL, VS, VC,
|
||||
0b1000u, 0b1001u, 0b1010u, 0b1011u, // HI, LS, GE, LT,
|
||||
0b1100u, 0b1101u, 0b1110u, 0b1111u)] uint cond) // GT, LE, AL, NV>
|
||||
{
|
||||
opcodes |= ((cond & 15) << 12);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(z);
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0(b);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
60
src/Ryujinx.Tests/Cpu/CpuTestSimdFmov.cs
Normal file
60
src/Ryujinx.Tests/Cpu/CpuTestSimdFmov.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
#define SimdFmov
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdFmov")]
|
||||
public sealed class CpuTestSimdFmov : CpuTest
|
||||
{
|
||||
#if SimdFmov
|
||||
|
||||
#region "ValueSource"
|
||||
private static uint[] _F_Mov_Si_S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E201000u // FMOV S0, #2.0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mov_Si_D_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x1E601000u // FMOV D0, #2.0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Si_S([ValueSource(nameof(_F_Mov_Si_S_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint imm8)
|
||||
{
|
||||
opcodes |= ((imm8 & 0xFFu) << 13);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Si_D([ValueSource(nameof(_F_Mov_Si_D_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint imm8)
|
||||
{
|
||||
opcodes |= ((imm8 & 0xFFu) << 13);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(z);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
395
src/Ryujinx.Tests/Cpu/CpuTestSimdImm.cs
Normal file
395
src/Ryujinx.Tests/Cpu/CpuTestSimdImm.cs
Normal file
|
@ -0,0 +1,395 @@
|
|||
#define SimdImm
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdImm")]
|
||||
public sealed class CpuTestSimdImm : CpuTest
|
||||
{
|
||||
#if SimdImm
|
||||
|
||||
#region "Helper methods"
|
||||
// abcdefgh -> aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh
|
||||
private static ulong ExpandImm8(byte imm8)
|
||||
{
|
||||
ulong imm64 = 0ul;
|
||||
|
||||
for (int i = 0, j = 0; i < 8; i++, j += 8)
|
||||
{
|
||||
if (((imm8 >> i) & 0b1) != 0)
|
||||
{
|
||||
imm64 |= 0b11111111ul << j;
|
||||
}
|
||||
}
|
||||
|
||||
return imm64;
|
||||
}
|
||||
|
||||
// aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh -> abcdefgh
|
||||
private static byte ShrinkImm64(ulong imm64)
|
||||
{
|
||||
byte imm8 = 0;
|
||||
|
||||
for (int i = 0, j = 0; i < 8; i++, j += 8)
|
||||
{
|
||||
if (((imm64 >> j) & 0b11111111ul) != 0ul) // Note: no format check.
|
||||
{
|
||||
imm8 |= (byte)(0b1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
return imm8;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _2S_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _4H_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static IEnumerable<byte> _8BIT_IMM_()
|
||||
{
|
||||
yield return 0x00;
|
||||
yield return 0x7F;
|
||||
yield return 0x80;
|
||||
yield return 0xFF;
|
||||
|
||||
for (int cnt = 1; cnt <= RndCntImm8; cnt++)
|
||||
{
|
||||
byte imm8 = TestContext.CurrentContext.Random.NextByte();
|
||||
|
||||
yield return imm8;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _64BIT_IMM_()
|
||||
{
|
||||
yield return ExpandImm8(0x00);
|
||||
yield return ExpandImm8(0x7F);
|
||||
yield return ExpandImm8(0x80);
|
||||
yield return ExpandImm8(0xFF);
|
||||
|
||||
for (int cnt = 1; cnt <= RndCntImm64; cnt++)
|
||||
{
|
||||
byte imm8 = TestContext.CurrentContext.Random.NextByte();
|
||||
|
||||
yield return ExpandImm8(imm8);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Bic_Orr_Vi_16bit_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x2F009400u, // BIC V0.4H, #0
|
||||
0x0F009400u // ORR V0.4H, #0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Bic_Orr_Vi_32bit_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x2F001400u, // BIC V0.2S, #0
|
||||
0x0F001400u // ORR V0.2S, #0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mov_Vi_2S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0F00F400u // FMOV V0.2S, #2.0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mov_Vi_4S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x4F00F400u // FMOV V0.4S, #2.0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mov_Vi_2D_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x6F00F400u // FMOV V0.2D, #2.0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Movi_V_8bit_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0F00E400u // MOVI V0.8B, #0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Movi_Mvni_V_16bit_shifted_imm_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0F008400u, // MOVI V0.4H, #0
|
||||
0x2F008400u // MVNI V0.4H, #0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Movi_Mvni_V_32bit_shifted_imm_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0F000400u, // MOVI V0.2S, #0
|
||||
0x2F000400u // MVNI V0.2S, #0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Movi_Mvni_V_32bit_shifting_ones_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0F00C400u, // MOVI V0.2S, #0, MSL #8
|
||||
0x2F00C400u // MVNI V0.2S, #0, MSL #8
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Movi_V_64bit_scalar_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x2F00E400u // MOVI D0, #0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Movi_V_64bit_vector_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x6F00E400u // MOVI V0.2D, #0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCntImm8 = 2;
|
||||
private const int RndCntImm64 = 2;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Bic_Orr_Vi_16bit([ValueSource(nameof(_Bic_Orr_Vi_16bit_))] uint opcodes,
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b0u, 0b1u)] uint amount, // <0, 8>
|
||||
[Values(0b0u, 0b1u)] uint q) // <4H, 8H>
|
||||
{
|
||||
uint abc = (imm8 & 0xE0u) >> 5;
|
||||
uint defgh = (imm8 & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
opcodes |= ((amount & 1) << 13);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Bic_Orr_Vi_32bit([ValueSource(nameof(_Bic_Orr_Vi_32bit_))] uint opcodes,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint amount, // <0, 8, 16, 24>
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
uint abc = (imm8 & 0xE0u) >> 5;
|
||||
uint defgh = (imm8 & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
opcodes |= ((amount & 3) << 13);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Vi_2S([ValueSource(nameof(_F_Mov_Vi_2S_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint abcdefgh)
|
||||
{
|
||||
uint abc = (abcdefgh & 0xE0u) >> 5;
|
||||
uint defgh = (abcdefgh & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(z);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Vi_4S([ValueSource(nameof(_F_Mov_Vi_4S_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint abcdefgh)
|
||||
{
|
||||
uint abc = (abcdefgh & 0xE0u) >> 5;
|
||||
uint defgh = (abcdefgh & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
|
||||
SingleOpcode(opcodes);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mov_Vi_2D([ValueSource(nameof(_F_Mov_Vi_2D_))] uint opcodes,
|
||||
[Range(0u, 255u, 1u)] uint abcdefgh)
|
||||
{
|
||||
uint abc = (abcdefgh & 0xE0u) >> 5;
|
||||
uint defgh = (abcdefgh & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
|
||||
SingleOpcode(opcodes);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_V_8bit([ValueSource(nameof(_Movi_V_8bit_))] uint opcodes,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
uint abc = (imm8 & 0xE0u) >> 5;
|
||||
uint defgh = (imm8 & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(q == 0u ? z : 0ul);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_Mvni_V_16bit_shifted_imm([ValueSource(nameof(_Movi_Mvni_V_16bit_shifted_imm_))] uint opcodes,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b0u, 0b1u)] uint amount, // <0, 8>
|
||||
[Values(0b0u, 0b1u)] uint q) // <4H, 8H>
|
||||
{
|
||||
uint abc = (imm8 & 0xE0u) >> 5;
|
||||
uint defgh = (imm8 & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
opcodes |= ((amount & 1) << 13);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(q == 0u ? z : 0ul);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_Mvni_V_32bit_shifted_imm([ValueSource(nameof(_Movi_Mvni_V_32bit_shifted_imm_))] uint opcodes,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b00u, 0b01u, 0b10u, 0b11u)] uint amount, // <0, 8, 16, 24>
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
uint abc = (imm8 & 0xE0u) >> 5;
|
||||
uint defgh = (imm8 & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
opcodes |= ((amount & 3) << 13);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(q == 0u ? z : 0ul);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_Mvni_V_32bit_shifting_ones([ValueSource(nameof(_Movi_Mvni_V_32bit_shifting_ones_))] uint opcodes,
|
||||
[ValueSource(nameof(_8BIT_IMM_))] byte imm8,
|
||||
[Values(0b0u, 0b1u)] uint amount, // <8, 16>
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
uint abc = (imm8 & 0xE0u) >> 5;
|
||||
uint defgh = (imm8 & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
opcodes |= ((amount & 1) << 12);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(q == 0u ? z : 0ul);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_V_64bit_scalar([ValueSource(nameof(_Movi_V_64bit_scalar_))] uint opcodes,
|
||||
[ValueSource(nameof(_64BIT_IMM_))] ulong imm)
|
||||
{
|
||||
byte imm8 = ShrinkImm64(imm);
|
||||
|
||||
uint abc = (imm8 & 0xE0u) >> 5;
|
||||
uint defgh = (imm8 & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(z);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Movi_V_64bit_vector([ValueSource(nameof(_Movi_V_64bit_vector_))] uint opcodes,
|
||||
[ValueSource(nameof(_64BIT_IMM_))] ulong imm)
|
||||
{
|
||||
byte imm8 = ShrinkImm64(imm);
|
||||
|
||||
uint abc = (imm8 & 0xE0u) >> 5;
|
||||
uint defgh = (imm8 & 0x1Fu);
|
||||
|
||||
opcodes |= (abc << 16) | (defgh << 5);
|
||||
|
||||
SingleOpcode(opcodes);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
689
src/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs
Normal file
689
src/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs
Normal file
|
@ -0,0 +1,689 @@
|
|||
#define SimdIns
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdIns")]
|
||||
public sealed class CpuTestSimdIns : CpuTest
|
||||
{
|
||||
#if SimdIns
|
||||
|
||||
#region "ValueSource"
|
||||
private static ulong[] _1D_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _2S_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _4H_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B4H_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B4H2S_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static uint[] _W_()
|
||||
{
|
||||
return new[] { 0x00000000u, 0x0000007Fu,
|
||||
0x00000080u, 0x000000FFu,
|
||||
0x00007FFFu, 0x00008000u,
|
||||
0x0000FFFFu, 0x7FFFFFFFu,
|
||||
0x80000000u, 0xFFFFFFFFu };
|
||||
}
|
||||
|
||||
private static ulong[] _X_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, W<n>")]
|
||||
public void Dup_Gp_W([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(0, 1, 2)] int size, // Q0: <8B, 4H, 2S>
|
||||
[Values(0b0u, 0b1u)] uint q) // Q1: <16B, 8H, 4S>
|
||||
{
|
||||
uint imm5 = (1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E000C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= ((q & 1) << 30);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, X<n>")]
|
||||
public void Dup_Gp_X([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_X_))] ulong xn)
|
||||
{
|
||||
uint opcode = 0x4E080C00; // DUP V0.2D, X0
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP B0, V1.B[<index>]")]
|
||||
public void Dup_S_B([ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x5E000420; // RESERVED
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP H0, V1.H[<index>]")]
|
||||
public void Dup_S_H([ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x5E000420; // RESERVED
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP S0, V1.S[<index>]")]
|
||||
public void Dup_S_S([ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
const int size = 2;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x5E000420; // RESERVED
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP D0, V1.D[<index>]")]
|
||||
public void Dup_S_D([ValueSource(nameof(_1D_))] ulong a,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
const int size = 3;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x5E000420; // RESERVED
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.B[<index>]")]
|
||||
public void Dup_V_8B_16B([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.H[<index>]")]
|
||||
public void Dup_V_4H_8H([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <4H, 8H>
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.S[<index>]")]
|
||||
public void Dup_V_2S_4S([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
const int size = 2;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("DUP <Vd>.<T>, <Vn>.D[<index>]")]
|
||||
public void Dup_V_2D([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource(nameof(_1D_))] ulong z,
|
||||
[ValueSource(nameof(_1D_))] ulong a,
|
||||
[Values(0u, 1u)] uint index,
|
||||
[Values(0b1u)] uint q) // <2D>
|
||||
{
|
||||
const int size = 3;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("INS <Vd>.B[<index>], W<n>")]
|
||||
public void Ins_Gp_WB([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x4E001C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("INS <Vd>.H[<index>], W<n>")]
|
||||
public void Ins_Gp_WH([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x4E001C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("INS <Vd>.S[<index>], W<n>")]
|
||||
public void Ins_Gp_WS([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_W_))] uint wn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
const int size = 2;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x4E001C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcode, x1: wn, x31: w31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("INS <Vd>.D[<index>], X<n>")]
|
||||
public void Ins_Gp_XD([Values(0u)] uint rd,
|
||||
[Values(1u, 31u)] uint rn,
|
||||
[ValueSource(nameof(_1D_))] ulong z,
|
||||
[ValueSource(nameof(_X_))] ulong xn,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
const int size = 3;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x4E001C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
|
||||
SingleOpcode(opcode, x1: xn, x31: x31, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("INS <Vd>.B[<index1>], <Vn>.B[<index2>]")]
|
||||
public void Ins_V_BB([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint dstIndex,
|
||||
[Values(0u, 15u)] uint srcIndex)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
uint imm5 = (dstIndex << (size + 1) | 1u << size) & 0x1Fu;
|
||||
uint imm4 = (srcIndex << size) & 0xFu;
|
||||
|
||||
uint opcode = 0x6E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= (imm4 << 11);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("INS <Vd>.H[<index1>], <Vn>.H[<index2>]")]
|
||||
public void Ins_V_HH([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint dstIndex,
|
||||
[Values(0u, 7u)] uint srcIndex)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
uint imm5 = (dstIndex << (size + 1) | 1u << size) & 0x1Fu;
|
||||
uint imm4 = (srcIndex << size) & 0xFu;
|
||||
|
||||
uint opcode = 0x6E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= (imm4 << 11);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("INS <Vd>.S[<index1>], <Vn>.S[<index2>]")]
|
||||
public void Ins_V_SS([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint dstIndex,
|
||||
[Values(0u, 1u, 2u, 3u)] uint srcIndex)
|
||||
{
|
||||
const int size = 2;
|
||||
|
||||
uint imm5 = (dstIndex << (size + 1) | 1u << size) & 0x1Fu;
|
||||
uint imm4 = (srcIndex << size) & 0xFu;
|
||||
|
||||
uint opcode = 0x6E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= (imm4 << 11);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("INS <Vd>.D[<index1>], <Vn>.D[<index2>]")]
|
||||
public void Ins_V_DD([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[ValueSource(nameof(_1D_))] ulong z,
|
||||
[ValueSource(nameof(_1D_))] ulong a,
|
||||
[Values(0u, 1u)] uint dstIndex,
|
||||
[Values(0u, 1u)] uint srcIndex)
|
||||
{
|
||||
const int size = 3;
|
||||
|
||||
uint imm5 = (dstIndex << (size + 1) | 1u << size) & 0x1Fu;
|
||||
uint imm4 = (srcIndex << size) & 0xFu;
|
||||
|
||||
uint opcode = 0x6E000400; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
opcode |= (imm4 << 11);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMOV <Wd>, <Vn>.B[<index>]")]
|
||||
public void Smov_S_BW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E002C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32;
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, x0: x0, x31: w31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMOV <Wd>, <Vn>.H[<index>]")]
|
||||
public void Smov_S_HW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E002C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32;
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, x0: x0, x31: w31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMOV <Xd>, <Vn>.B[<index>]")]
|
||||
public void Smov_S_BX([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x4E002C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, x31: x31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMOV <Xd>, <Vn>.H[<index>]")]
|
||||
public void Smov_S_HX([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x4E002C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, x31: x31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SMOV <Xd>, <Vn>.S[<index>]")]
|
||||
public void Smov_S_SX([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
const int size = 2;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x4E002C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, x31: x31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UMOV <Wd>, <Vn>.B[<index>]")]
|
||||
public void Umov_S_BW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_8B_))] ulong a,
|
||||
[Values(0u, 15u)] uint index)
|
||||
{
|
||||
const int size = 0;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E003C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32;
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, x0: x0, x31: w31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UMOV <Wd>, <Vn>.H[<index>]")]
|
||||
public void Umov_S_HW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[Values(0u, 7u)] uint index)
|
||||
{
|
||||
const int size = 1;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E003C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32;
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, x0: x0, x31: w31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UMOV <Wd>, <Vn>.S[<index>]")]
|
||||
public void Umov_S_SW([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
const int size = 2;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x0E003C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32;
|
||||
uint w31 = TestContext.CurrentContext.Random.NextUInt();
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, x0: x0, x31: w31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UMOV <Xd>, <Vn>.D[<index>]")]
|
||||
public void Umov_S_DX([Values(0u, 31u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[ValueSource(nameof(_1D_))] ulong a,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
const int size = 3;
|
||||
|
||||
uint imm5 = (index << (size + 1) | 1u << size) & 0x1Fu;
|
||||
|
||||
uint opcode = 0x4E003C00; // RESERVED
|
||||
opcode |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcode |= (imm5 << 16);
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
|
||||
SingleOpcode(opcode, x31: x31, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
153
src/Ryujinx.Tests/Cpu/CpuTestSimdLogical32.cs
Normal file
153
src/Ryujinx.Tests/Cpu/CpuTestSimdLogical32.cs
Normal file
|
@ -0,0 +1,153 @@
|
|||
#define SimdLogical32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdLogical32")]
|
||||
public sealed class CpuTestSimdLogical32 : CpuTest32
|
||||
{
|
||||
#if SimdLogical32
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _8B4H2S_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Vbic_Vbif_Vbit_Vbsl_Vand_Vorn_Vorr_Veor_I_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2100110u, // VBIC D0, D0, D0
|
||||
0xf3300110u, // VBIF D0, D0, D0
|
||||
0xf3200110u, // VBIT D0, D0, D0
|
||||
0xf3100110u, // VBSL D0, D0, D0
|
||||
0xf2000110u, // VAND D0, D0, D0
|
||||
0xf2300110u, // VORN D0, D0, D0
|
||||
0xf2200110u, // VORR D0, D0, D0
|
||||
0xf3000110u // VEOR D0, D0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vbic_Vorr_II_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2800130u, // VBIC.I32 D0, #0 (A1)
|
||||
0xf2800930u, // VBIC.I16 D0, #0 (A2)
|
||||
0xf2800110u, // VORR.I32 D0, #0 (A1)
|
||||
0xf2800910u // VORR.I16 D0, #0 (A2)
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vbic_Vbif_Vbit_Vbsl_Vand_Vorn_Vorr_Veor_I([ValueSource(nameof(_Vbic_Vbif_Vbit_Vbsl_Vand_Vorn_Vorr_Veor_I_))] uint opcode,
|
||||
[Range(0u, 5u)] uint rd,
|
||||
[Range(0u, 5u)] uint rn,
|
||||
[Range(0u, 5u)] uint rm,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] ulong z,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] ulong a,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
rn >>= 1; rn <<= 1;
|
||||
rm >>= 1; rm <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
V128 v1 = MakeVectorE0E1(a, ~a);
|
||||
V128 v2 = MakeVectorE0E1(b, ~b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vbic_Vorr_II([ValueSource(nameof(_Vbic_Vorr_II_))] uint opcode,
|
||||
[Values(0u, 1u)] uint rd,
|
||||
[Values(ulong.MinValue, ulong.MaxValue)] ulong z,
|
||||
[Values(byte.MinValue, byte.MaxValue)] byte imm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint cMode,
|
||||
[Values] bool q)
|
||||
{
|
||||
if ((opcode & 0x800) != 0) // cmode<3> == '1' (A2)
|
||||
{
|
||||
cMode &= 1;
|
||||
}
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((uint)imm & 0xf) << 0;
|
||||
opcode |= ((uint)imm & 0x70) << 12;
|
||||
opcode |= ((uint)imm & 0x80) << 17;
|
||||
opcode |= (cMode & 0x3) << 9;
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VTST.<dt> <Vd>, <Vn>, <Vm>")]
|
||||
public void Vtst([Range(0u, 5u)] uint rd,
|
||||
[Range(0u, 5u)] uint rn,
|
||||
[Range(0u, 5u)] uint rm,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong z,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong a,
|
||||
[ValueSource(nameof(_8B4H2S_))] ulong b,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf2000810u; // VTST.8 D0, D0, D0
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
rn >>= 1; rn <<= 1;
|
||||
rm >>= 1; rm <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
opcode |= (size & 0x3) << 20;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
V128 v1 = MakeVectorE0E1(a, ~a);
|
||||
V128 v2 = MakeVectorE0E1(b, ~b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
331
src/Ryujinx.Tests/Cpu/CpuTestSimdMemory32.cs
Normal file
331
src/Ryujinx.Tests/Cpu/CpuTestSimdMemory32.cs
Normal file
|
@ -0,0 +1,331 @@
|
|||
#define SimdMemory32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdMemory32")]
|
||||
public sealed class CpuTestSimdMemory32 : CpuTest32
|
||||
{
|
||||
#if SimdMemory32
|
||||
|
||||
private uint[] _ldStModes =
|
||||
{
|
||||
// LD1
|
||||
0b0111,
|
||||
0b1010,
|
||||
0b0110,
|
||||
0b0010,
|
||||
|
||||
// LD2
|
||||
0b1000,
|
||||
0b1001,
|
||||
0b0011,
|
||||
|
||||
// LD3
|
||||
0b0100,
|
||||
0b0101,
|
||||
|
||||
// LD4
|
||||
0b0000,
|
||||
0b0001
|
||||
};
|
||||
|
||||
[Test, Pairwise, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (single n element structure)")]
|
||||
public void Vldn_Single([Values(0u, 1u, 2u)] uint size,
|
||||
[Values(0u, 13u)] uint rn,
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 7u)] uint index,
|
||||
[Range(0u, 3u)] uint n,
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
|
||||
uint opcode = 0xf4a00000u; // VLD1.8 {D0[0]}, [R0], R0
|
||||
|
||||
opcode |= ((size & 3) << 10) | ((rn & 15) << 16) | (rm & 15);
|
||||
|
||||
uint index_align = (index << (int)(1 + size)) & 15;
|
||||
|
||||
opcode |= (index_align) << 4;
|
||||
|
||||
opcode |= ((vd & 0x10) << 18);
|
||||
opcode |= ((vd & 0xf) << 12);
|
||||
|
||||
opcode |= (n & 3) << 8; // LD1 is 0, LD2 is 1 etc.
|
||||
|
||||
SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (all lanes)")]
|
||||
public void Vldn_All([Values(0u, 13u)] uint rn,
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 3u)] uint n,
|
||||
[Range(0u, 2u)] uint size,
|
||||
[Values] bool t,
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
|
||||
uint opcode = 0xf4a00c00u; // VLD1.8 {D0[0]}, [R0], R0
|
||||
|
||||
opcode |= ((size & 3) << 6) | ((rn & 15) << 16) | (rm & 15);
|
||||
|
||||
opcode |= ((vd & 0x10) << 18);
|
||||
opcode |= ((vd & 0xf) << 12);
|
||||
|
||||
opcode |= (n & 3) << 8; // LD1 is 0, LD2 is 1 etc.
|
||||
if (t) opcode |= 1 << 5;
|
||||
|
||||
SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (multiple n element structures)")]
|
||||
public void Vldn_Pair([Values(0u, 1u, 2u, 3u)] uint size,
|
||||
[Values(0u, 13u)] uint rn,
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 10u)] uint mode,
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
|
||||
uint opcode = 0xf4200000u; // VLD4.8 {D0, D1, D2, D3}, [R0], R0
|
||||
|
||||
if (mode > 3 && size == 3)
|
||||
{
|
||||
// A size of 3 is only valid for VLD1.
|
||||
size = 2;
|
||||
}
|
||||
|
||||
opcode |= ((size & 3) << 6) | ((rn & 15) << 16) | (rm & 15) | (_ldStModes[mode] << 8);
|
||||
|
||||
opcode |= ((vd & 0x10) << 18);
|
||||
opcode |= ((vd & 0xf) << 12);
|
||||
|
||||
SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VSTn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (single n element structure)")]
|
||||
public void Vstn_Single([Values(0u, 1u, 2u)] uint size,
|
||||
[Values(0u, 13u)] uint rn,
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 7u)] uint index,
|
||||
[Range(0u, 3u)] uint n,
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
|
||||
(V128 vec1, V128 vec2, V128 vec3, V128 vec4) = GenerateTestVectors();
|
||||
|
||||
uint opcode = 0xf4800000u; // VST1.8 {D0[0]}, [R0], R0
|
||||
|
||||
opcode |= ((size & 3) << 10) | ((rn & 15) << 16) | (rm & 15);
|
||||
|
||||
uint index_align = (index << (int)(1 + size)) & 15;
|
||||
|
||||
opcode |= (index_align) << 4;
|
||||
|
||||
opcode |= ((vd & 0x10) << 18);
|
||||
opcode |= ((vd & 0xf) << 12);
|
||||
|
||||
opcode |= (n & 3) << 8; // ST1 is 0, ST2 is 1 etc.
|
||||
|
||||
SingleOpcode(opcode, r0: 0x2500, r1: offset, v1: vec1, v2: vec2, v3: vec3, v4: vec4, sp: 0x2500);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VSTn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (multiple n element structures)")]
|
||||
public void Vstn_Pair([Values(0u, 1u, 2u, 3u)] uint size,
|
||||
[Values(0u, 13u)] uint rn,
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 10u)] uint mode,
|
||||
[Values(0x0u)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
|
||||
(V128 vec1, V128 vec2, V128 vec3, V128 vec4) = GenerateTestVectors();
|
||||
|
||||
uint opcode = 0xf4000000u; // VST4.8 {D0, D1, D2, D3}, [R0], R0
|
||||
|
||||
if (mode > 3 && size == 3)
|
||||
{
|
||||
// A size of 3 is only valid for VST1.
|
||||
size = 2;
|
||||
}
|
||||
|
||||
opcode |= ((size & 3) << 6) | ((rn & 15) << 16) | (rm & 15) | (_ldStModes[mode] << 8);
|
||||
|
||||
opcode |= ((vd & 0x10) << 18);
|
||||
opcode |= ((vd & 0xf) << 12);
|
||||
|
||||
SingleOpcode(opcode, r0: 0x2500, r1: offset, v1: vec1, v2: vec2, v3: vec3, v4: vec4, sp: 0x2500);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VLDM.<size> <Rn>{!}, <d/sreglist>")]
|
||||
public void Vldm([Values(0u, 13u)] uint rn,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 2u)] uint mode,
|
||||
[Values(0x1u, 0x32u)] uint regs,
|
||||
[Values] bool single)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
|
||||
uint opcode = 0xec100a00u; // VST4.8 {D0, D1, D2, D3}, [R0], R0
|
||||
|
||||
uint[] vldmModes =
|
||||
{
|
||||
// Note: 3rd 0 leaves a space for "D".
|
||||
0b0100, // Increment after.
|
||||
0b0101, // Increment after. (!)
|
||||
0b1001 // Decrement before. (!)
|
||||
};
|
||||
|
||||
opcode |= ((vldmModes[mode] & 15) << 21);
|
||||
opcode |= ((rn & 15) << 16);
|
||||
|
||||
opcode |= ((vd & 0x10) << 18);
|
||||
opcode |= ((vd & 0xf) << 12);
|
||||
|
||||
opcode |= ((uint)(single ? 0 : 1) << 8);
|
||||
|
||||
if (!single) regs = (regs << 1); // Low bit must be 0 - must be even number of registers.
|
||||
uint regSize = single ? 1u : 2u;
|
||||
|
||||
if (vd + (regs / regSize) > 32) // Can't address further than S31 or D31.
|
||||
{
|
||||
regs -= (vd + (regs / regSize)) - 32;
|
||||
}
|
||||
|
||||
if (regs / regSize > 16) // Can't do more than 16 registers at a time.
|
||||
{
|
||||
regs = 16 * regSize;
|
||||
}
|
||||
|
||||
opcode |= regs & 0xff;
|
||||
|
||||
SingleOpcode(opcode, r0: 0x2500, sp: 0x2500);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VLDR.<size> <Sd>, [<Rn> {, #{+/-}<imm>}]")]
|
||||
public void Vldr([Values(2u, 3u)] uint size, // FP16 is not supported for now
|
||||
[Values(0u)] uint rn,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint sd,
|
||||
[Values(0x0u)] uint imm,
|
||||
[Values] bool sub)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
|
||||
uint opcode = 0xed900a00u; // VLDR.32 S0, [R0, #0]
|
||||
opcode |= ((size & 3) << 8) | ((rn & 15) << 16);
|
||||
|
||||
if (sub)
|
||||
{
|
||||
opcode &= ~(uint)(1 << 23);
|
||||
}
|
||||
|
||||
if (size == 2)
|
||||
{
|
||||
opcode |= ((sd & 0x1) << 22);
|
||||
opcode |= ((sd & 0x1e) << 11);
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode |= ((sd & 0x10) << 18);
|
||||
opcode |= ((sd & 0xf) << 12);
|
||||
}
|
||||
opcode |= imm & 0xff;
|
||||
|
||||
SingleOpcode(opcode, r0: 0x2500);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VSTR.<size> <Sd>, [<Rn> {, #{+/-}<imm>}]")]
|
||||
public void Vstr([Values(2u, 3u)] uint size, // FP16 is not supported for now
|
||||
[Values(0u)] uint rn,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint sd,
|
||||
[Values(0x0u)] uint imm,
|
||||
[Values] bool sub)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(0, data);
|
||||
|
||||
uint opcode = 0xed800a00u; // VSTR.32 S0, [R0, #0]
|
||||
opcode |= ((size & 3) << 8) | ((rn & 15) << 16);
|
||||
|
||||
if (sub)
|
||||
{
|
||||
opcode &= ~(uint)(1 << 23);
|
||||
}
|
||||
|
||||
if (size == 2)
|
||||
{
|
||||
opcode |= ((sd & 0x1) << 22);
|
||||
opcode |= ((sd & 0x1e) << 11);
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode |= ((sd & 0x10) << 18);
|
||||
opcode |= ((sd & 0xf) << 12);
|
||||
}
|
||||
opcode |= imm & 0xff;
|
||||
|
||||
(V128 vec1, V128 vec2, _, _) = GenerateTestVectors();
|
||||
|
||||
SingleOpcode(opcode, r0: 0x2500, v0: vec1, v1: vec2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
private (V128, V128, V128, V128) GenerateTestVectors()
|
||||
{
|
||||
return (
|
||||
new V128(-12.43f, 1872.23f, 4456.23f, -5622.2f),
|
||||
new V128(0.0f, float.NaN, float.PositiveInfinity, float.NegativeInfinity),
|
||||
new V128(1.23e10f, -0.0f, -0.123f, 0.123f),
|
||||
new V128(float.Epsilon, 3.5f, 925.23f, -104.9f)
|
||||
);
|
||||
}
|
||||
|
||||
private byte[] GenerateVectorSequence(int length)
|
||||
{
|
||||
int floatLength = length >> 2;
|
||||
float[] data = new float[floatLength];
|
||||
|
||||
for (int i = 0; i < floatLength; i++)
|
||||
{
|
||||
data[i] = i + (i / 9f);
|
||||
}
|
||||
|
||||
var result = new byte[length];
|
||||
Buffer.BlockCopy(data, 0, result, 0, result.Length);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
599
src/Ryujinx.Tests/Cpu/CpuTestSimdMov32.cs
Normal file
599
src/Ryujinx.Tests/Cpu/CpuTestSimdMov32.cs
Normal file
|
@ -0,0 +1,599 @@
|
|||
#define SimdMov32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdMov32")]
|
||||
public sealed class CpuTestSimdMov32 : CpuTest32
|
||||
{
|
||||
#if SimdMov32
|
||||
private const int RndCntImm = 2;
|
||||
|
||||
[Test, Pairwise, Description("VMOV.I<size> <Dd/Qd>, #<imm>")]
|
||||
public void Movi_V([Range(0u, 10u)] uint variant,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0x0u)] uint imm,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint[] variants =
|
||||
{
|
||||
// I32
|
||||
0b0000_0,
|
||||
0b0010_0,
|
||||
0b0100_0,
|
||||
0b0110_0,
|
||||
|
||||
// I16
|
||||
0b1000_0,
|
||||
0b1010_0,
|
||||
|
||||
// DT
|
||||
0b1100_0,
|
||||
0b1101_0,
|
||||
0b1110_0,
|
||||
0b1111_0,
|
||||
|
||||
0b1110_1
|
||||
};
|
||||
|
||||
uint opcode = 0xf2800010u; // VMOV.I32 D0, #0
|
||||
|
||||
uint cmodeOp = variants[variant];
|
||||
|
||||
if (q)
|
||||
{
|
||||
vd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((cmodeOp & 1) << 5) | ((cmodeOp & 0x1e) << 7);
|
||||
opcode |= (q ? 1u : 0u) << 6;
|
||||
opcode |= (imm & 0xf) | ((imm & 0x70) << 12) | ((imm & 0x80) << 16);
|
||||
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
|
||||
SingleOpcode(opcode);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMOV.F<size> <Sd>, #<imm>")]
|
||||
public void Movi_S([Range(2u, 3u)] uint size,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0x0u)] uint imm)
|
||||
{
|
||||
uint opcode = 0xeeb00800u;
|
||||
opcode |= (size & 3) << 8;
|
||||
opcode |= (imm & 0xf) | ((imm & 0xf0) << 12);
|
||||
|
||||
if (size == 2)
|
||||
{
|
||||
opcode |= ((vd & 0x1) << 22);
|
||||
opcode |= ((vd & 0x1e) << 11);
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode |= ((vd & 0x10) << 18);
|
||||
opcode |= ((vd & 0xf) << 12);
|
||||
}
|
||||
|
||||
SingleOpcode(opcode);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMOV <Rd>, <Sd>")]
|
||||
public void Mov_GP([Values(0u, 1u, 2u, 3u)] uint vn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt,
|
||||
[Random(RndCntImm)] uint valueRn,
|
||||
[Random(RndCntImm)] ulong valueVn1,
|
||||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool op)
|
||||
{
|
||||
uint opcode = 0xee000a10u; // VMOV S0, R0
|
||||
opcode |= (vn & 1) << 7;
|
||||
opcode |= (vn & 0x1e) << 15;
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
|
||||
if (op) opcode |= 1 << 20;
|
||||
|
||||
SingleOpcode(opcode, r0: valueRn, r1: valueRn, r2: valueRn, r3: valueRn, v0: new V128(valueVn1, valueVn2));
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMOV.<size> <Rt>, <Dn[x]>")]
|
||||
public void Mov_GP_Elem([Range(0u, 7u)] uint vn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt,
|
||||
[Range(0u, 2u)] uint size,
|
||||
[Range(0u, 7u)] uint index,
|
||||
[Random(1)] uint valueRn,
|
||||
[Random(1)] ulong valueVn1,
|
||||
[Random(1)] ulong valueVn2,
|
||||
[Values] bool op,
|
||||
[Values] bool u)
|
||||
{
|
||||
uint opcode = 0xee000b10u; // VMOV.32 D0[0], R0
|
||||
|
||||
uint opEncode = 0b01000;
|
||||
switch (size)
|
||||
{
|
||||
case 0:
|
||||
opEncode = (0b1000) | index & 7;
|
||||
break;
|
||||
case 1:
|
||||
opEncode = (0b0001) | ((index & 3) << 1);
|
||||
break;
|
||||
case 2:
|
||||
opEncode = (index & 1) << 2;
|
||||
break;
|
||||
}
|
||||
|
||||
opcode |= ((opEncode >> 2) << 21) | ((opEncode & 3) << 5);
|
||||
|
||||
opcode |= (vn & 0x10) << 3;
|
||||
opcode |= (vn & 0xf) << 16;
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
|
||||
if (op)
|
||||
{
|
||||
opcode |= 1 << 20;
|
||||
if (u && size != 2)
|
||||
{
|
||||
opcode |= 1 << 23;
|
||||
}
|
||||
}
|
||||
|
||||
SingleOpcode(opcode, r0: valueRn, r1: valueRn, r2: valueRn, r3: valueRn, v0: new V128(valueVn1, valueVn2), v1: new V128(valueVn2, valueVn1));
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("(VMOV <Rt>, <Rt2>, <Dm>), (VMOV <Dm>, <Rt>, <Rt2>)")]
|
||||
public void Mov_GP_D([Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt2,
|
||||
[Random(RndCntImm)] uint valueRt1,
|
||||
[Random(RndCntImm)] uint valueRt2,
|
||||
[Random(RndCntImm)] ulong valueVn1,
|
||||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool op)
|
||||
{
|
||||
uint opcode = 0xec400b10u; // VMOV D0, R0, R0
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
opcode |= (rt2 & 0xf) << 16;
|
||||
|
||||
if (op)
|
||||
{
|
||||
opcode |= 1 << 20;
|
||||
}
|
||||
|
||||
SingleOpcode(opcode, r0: valueRt1, r1: valueRt2, r2: valueRt1, r3: valueRt2, v0: new V128(valueVn1, valueVn2));
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("(VMOV <Rt>, <Rt2>, <Sm>, <Sm1>), (VMOV <Sm>, <Sm1>, <Rt>, <Rt2>)")]
|
||||
public void Mov_GP_2([Range(0u, 7u)] uint vm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt2,
|
||||
[Random(RndCntImm)] uint valueRt1,
|
||||
[Random(RndCntImm)] uint valueRt2,
|
||||
[Random(RndCntImm)] ulong valueVn1,
|
||||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool op)
|
||||
{
|
||||
uint opcode = 0xec400a10u; // VMOV S0, S1, R0, R0
|
||||
opcode |= (vm & 1) << 5;
|
||||
opcode |= (vm & 0x1e) >> 1;
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
opcode |= (rt2 & 0xf) << 16;
|
||||
|
||||
if (op)
|
||||
{
|
||||
opcode |= 1 << 20;
|
||||
}
|
||||
|
||||
SingleOpcode(opcode, r0: valueRt1, r1: valueRt2, r2: valueRt1, r3: valueRt2, v0: new V128(valueVn1, valueVn2), v1: new V128(valueVn2, valueVn1));
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMOVN.<size> <Dt>, <Qm>")]
|
||||
public void Movn_V([Range(0u, 1u, 2u)] uint size,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 2u, 4u, 8u)] uint vm)
|
||||
{
|
||||
uint opcode = 0xf3b20200u; // VMOVN.I16 D0, Q0
|
||||
|
||||
opcode |= (size & 0x3) << 18;
|
||||
opcode |= ((vm & 0x10) << 1);
|
||||
opcode |= ((vm & 0xf) << 0);
|
||||
|
||||
opcode |= ((vd & 0x10) << 18);
|
||||
opcode |= ((vd & 0xf) << 12);
|
||||
|
||||
V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMOVL.<size> <Qd>, <Dm>")]
|
||||
public void Vmovl([Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 2u, 4u, 6u)] uint vd,
|
||||
[Values(1u, 2u, 4u)] uint imm3H,
|
||||
[Values] bool u)
|
||||
{
|
||||
// This is not VMOVL because imm3H = 0, but once
|
||||
// we shift in the imm3H value it turns into VMOVL.
|
||||
uint opcode = 0xf2800a10u; // VMOV.I16 D0, #0
|
||||
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
opcode |= (imm3H & 0x7) << 19;
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
}
|
||||
|
||||
V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMVN.<size> <Vt>, <Vm>")]
|
||||
public void Vmvn([Range(0u, 1u, 2u)] uint size,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 2u, 4u, 8u)] uint vm,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf3b00580u; // VMVN D0, D0
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
vm <<= 1;
|
||||
vd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= (size & 0x3) << 18;
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf) << 0;
|
||||
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
|
||||
V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMVN.I<size> <Dd/Qd>, #<imm>")]
|
||||
public void Mvni_V([Range(0u, 7u)] uint variant,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0x0u)] uint imm,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint[] variants =
|
||||
{
|
||||
// I32
|
||||
0b0000,
|
||||
0b0010,
|
||||
0b0100,
|
||||
0b0110,
|
||||
|
||||
// I16
|
||||
0b1000,
|
||||
0b1010,
|
||||
|
||||
// I32
|
||||
0b1100,
|
||||
0b1101,
|
||||
};
|
||||
|
||||
uint opcode = 0xf2800030u; // VMVN.I32 D0, #0
|
||||
|
||||
uint cmodeOp = variants[variant];
|
||||
|
||||
if (q)
|
||||
{
|
||||
vd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= (cmodeOp & 0xf) << 8;
|
||||
opcode |= (q ? 1u : 0u) << 6;
|
||||
opcode |= (imm & 0xf) | ((imm & 0x70) << 12) | ((imm & 0x80) << 16);
|
||||
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
|
||||
SingleOpcode(opcode);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VTRN.<size> <Vd>, <Vm>")]
|
||||
public void Vtrn([Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf3b20080u; // VTRN.8 D0, D0
|
||||
if (vm == vd)
|
||||
{
|
||||
return; // Undefined.
|
||||
}
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
vd <<= 1; vm <<= 1;
|
||||
}
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
opcode |= (size & 0x3) << 18;
|
||||
|
||||
V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VZIP.<size> <Vd>, <Vm>")]
|
||||
public void Vzip([Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf3b20180u; // VZIP.8 D0, D0
|
||||
if (vm == vd || (size == 2 && !q))
|
||||
{
|
||||
return; // Undefined.
|
||||
}
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
vd <<= 1; vm <<= 1;
|
||||
}
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
opcode |= (size & 0x3) << 18;
|
||||
|
||||
V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VUZP.<size> <Vd>, <Vm>")]
|
||||
public void Vuzp([Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf3b20100u; // VUZP.8 d0, d0
|
||||
if (vm == vd || (size == 2 && !q))
|
||||
{
|
||||
return; // Undefined.
|
||||
}
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
vd <<= 1; vm <<= 1;
|
||||
}
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
opcode |= (size & 0x3) << 18;
|
||||
|
||||
V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VTBL.8 <Dd>, {list}, <Dm>")]
|
||||
public void Vtbl([Range(0u, 6u)] uint vm, // Indices, include potentially invalid.
|
||||
[Range(4u, 12u)] uint vn, // Selection.
|
||||
[Values(0u, 1u)] uint vd, // Destinations.
|
||||
[Range(0u, 3u)] uint length,
|
||||
[Values] bool x)
|
||||
{
|
||||
uint opcode = 0xf3b00800u; // VTBL.8 D0, {D0}, D0
|
||||
if (vn + length > 31)
|
||||
{
|
||||
return; // Undefined.
|
||||
}
|
||||
|
||||
if (x)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
}
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
|
||||
opcode |= (vn & 0x10) << 3;
|
||||
opcode |= (vn & 0xf) << 16;
|
||||
opcode |= (length & 0x3) << 8;
|
||||
|
||||
var rnd = TestContext.CurrentContext.Random;
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v4 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v5 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
byte maxIndex = (byte)(length * 8 - 1);
|
||||
byte[] b0 = new byte[16];
|
||||
byte[] b1 = new byte[16];
|
||||
for (int i=0; i<16; i++)
|
||||
{
|
||||
b0[i] = rnd.NextByte(maxIndex);
|
||||
b1[i] = rnd.NextByte(maxIndex);
|
||||
}
|
||||
|
||||
V128 v0 = new V128(b0);
|
||||
V128 v1 = new V128(b1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3, v4: v4, v5: v5);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VEXT.8 {<Vd>,} <Vn>, <Vm>, #<imm>")]
|
||||
public void Vext([Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 15u)] uint imm4,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf2b00000; // VEXT.32 D0, D0, D0, #0
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
vd <<= 1; vm <<= 1; vn <<= 1;
|
||||
}
|
||||
else if (imm4 > 7)
|
||||
{
|
||||
return; // Undefined.
|
||||
}
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
opcode |= (vn & 0x10) << 3;
|
||||
opcode |= (vn & 0xf) << 16;
|
||||
opcode |= (imm4 & 0xf) << 8;
|
||||
|
||||
V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VDUP.<size> <Vd>, <Rt>")]
|
||||
public void Vdup_GP([Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCntImm)] uint valueRn,
|
||||
[Random(RndCntImm)] ulong valueVn1,
|
||||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xee800b10; // VDUP.32 d0, r0
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 21;
|
||||
vd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= (vd & 0x10) << 3;
|
||||
opcode |= (vd & 0xf) << 16;
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
|
||||
opcode |= (size & 1) << 5; // E
|
||||
opcode |= (size & 2) << 21; // B
|
||||
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, r0: valueRn, r1: valueRn, r2: valueRn, r3: valueRn, v0: new V128(valueVn1, valueVn2), v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VDUP.<size> <Vd>, <Dm[x]>")]
|
||||
public void Vdup_S([Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Range(0u, 7u)] uint index,
|
||||
[Random(RndCntImm)] ulong valueVn1,
|
||||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf3b00c00;
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
vd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
|
||||
uint imm4 = 0;
|
||||
switch (size)
|
||||
{
|
||||
case 0:
|
||||
imm4 |= 0b0100 | ((index & 1) << 3);
|
||||
break;
|
||||
case 1:
|
||||
imm4 |= 0b0010 | ((index & 3) << 2);
|
||||
break;
|
||||
case 2:
|
||||
imm4 |= 0b0001 | ((index & 7) << 1);
|
||||
break;
|
||||
}
|
||||
|
||||
opcode |= imm4 << 16;
|
||||
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: new V128(valueVn1, valueVn2), v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
4009
src/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs
Normal file
4009
src/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs
Normal file
File diff suppressed because it is too large
Load diff
883
src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs
Normal file
883
src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs
Normal file
|
@ -0,0 +1,883 @@
|
|||
#define SimdReg32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdReg32")]
|
||||
public sealed class CpuTestSimdReg32 : CpuTest32
|
||||
{
|
||||
#if SimdReg32
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _V_Add_Sub_Long_Wide_I_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2800000u, // VADDL.S8 Q0, D0, D0
|
||||
0xf2800100u, // VADDW.S8 Q0, Q0, D0
|
||||
0xf2800200u, // VSUBL.S8 Q0, D0, D0
|
||||
0xf2800300u // VSUBW.S8 Q0, Q0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vfma_Vfms_Vfnma_Vfnms_S_F32_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xEEA00A00u, // VFMA. F32 S0, S0, S0
|
||||
0xEEA00A40u, // VFMS. F32 S0, S0, S0
|
||||
0xEE900A40u, // VFNMA.F32 S0, S0, S0
|
||||
0xEE900A00u // VFNMS.F32 S0, S0, S0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vfma_Vfms_Vfnma_Vfnms_S_F64_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xEEA00B00u, // VFMA. F64 D0, D0, D0
|
||||
0xEEA00B40u, // VFMS. F64 D0, D0, D0
|
||||
0xEE900B40u, // VFNMA.F64 D0, D0, D0
|
||||
0xEE900B00u // VFNMS.F64 D0, D0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vfma_Vfms_V_F32_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xF2000C10u, // VFMA.F32 D0, D0, D0
|
||||
0xF2200C10u // VFMS.F32 D0, D0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vmla_Vmls_Vnmla_Vnmls_S_F32_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xEE000A00u, // VMLA. F32 S0, S0, S0
|
||||
0xEE000A40u, // VMLS. F32 S0, S0, S0
|
||||
0xEE100A40u, // VNMLA.F32 S0, S0, S0
|
||||
0xEE100A00u // VNMLS.F32 S0, S0, S0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vmla_Vmls_Vnmla_Vnmls_S_F64_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xEE000B00u, // VMLA. F64 D0, D0, D0
|
||||
0xEE000B40u, // VMLS. F64 D0, D0, D0
|
||||
0xEE100B40u, // VNMLA.F64 D0, D0, D0
|
||||
0xEE100B00u // VNMLS.F64 D0, D0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vmlal_Vmlsl_V_I_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2800800u, // VMLAL.S8 Q0, D0, D0
|
||||
0xf2800a00u // VMLSL.S8 Q0, D0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vp_Add_Max_Min_F_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf3000d00u, // VPADD.F32 D0, D0, D0
|
||||
0xf3000f00u, // VPMAX.F32 D0, D0, D0
|
||||
0xf3200f00u // VPMIN.F32 D0, D0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vp_Add_I_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2000b10u // VPADD.I8 D0, D0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _V_Pmax_Pmin_Rhadd_I_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2000a00u, // VPMAX .S8 D0, D0, D0
|
||||
0xf2000a10u, // VPMIN .S8 D0, D0, D0
|
||||
0xf2000100u, // VRHADD.S8 D0, D0, D0
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vq_Add_Sub_I_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2000050u, // VQADD.S8 Q0, Q0, Q0
|
||||
0xf2000250u // VQSUB.S8 Q0, Q0, Q0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _8B1D_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B4H2S1D_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
{
|
||||
yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x0000000080800000ul; // -Min Normal
|
||||
yield return 0x00000000807FFFFFul; // -Max Subnormal
|
||||
yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0000000000800000ul; // +Min Normal
|
||||
yield return 0x00000000007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x0000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0x00000000FF800000ul; // -Infinity
|
||||
yield return 0x000000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (grbg << 32) | rnd1;
|
||||
yield return (grbg << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _2S_F_()
|
||||
{
|
||||
yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x8080000080800000ul; // -Min Normal
|
||||
yield return 0x807FFFFF807FFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0080000000800000ul; // +Min Normal
|
||||
yield return 0x007FFFFF007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFF800000FF800000ul; // -Infinity
|
||||
yield return 0x7F8000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (rnd1 << 32) | rnd1;
|
||||
yield return (rnd2 << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1D_F_()
|
||||
{
|
||||
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
||||
yield return 0x8010000000000000ul; // -Min Normal
|
||||
yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
|
||||
yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
|
||||
yield return 0x0010000000000000ul; // +Min Normal
|
||||
yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000000000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFFF0000000000000ul; // -Infinity
|
||||
yield return 0x7FF0000000000000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
|
||||
yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
|
||||
yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalD();
|
||||
ulong rnd2 = GenSubnormalD();
|
||||
|
||||
yield return rnd1;
|
||||
yield return rnd2;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise, Description("SHA256H.32 <Qd>, <Qn>, <Qm>")]
|
||||
public void Sha256h_V([Values(0xF3000C40u)] uint opcode,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(2u)] uint rn,
|
||||
[Values(4u)] uint rm,
|
||||
[Values(0xAEE65C11943FB939ul)] ulong z0,
|
||||
[Values(0xA89A87F110291DA3ul)] ulong z1,
|
||||
[Values(0xE9F766DB7A49EA7Dul)] ulong a0,
|
||||
[Values(0x3053F46B0C2F3507ul)] ulong a1,
|
||||
[Values(0x6E86A473B9D4A778ul)] ulong b0,
|
||||
[Values(0x7BE4F9E638156BB1ul)] ulong b1,
|
||||
[Values(0x1F1DC4A98DA9C132ul)] ulong resultL,
|
||||
[Values(0xDB9A2A7B47031A0Dul)] ulong resultH)
|
||||
{
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z0, z1);
|
||||
V128 v1 = MakeVectorE0E1(a0, a1);
|
||||
V128 v2 = MakeVectorE0E1(b0, b1);
|
||||
|
||||
ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, runUnicorn: false);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
|
||||
// Unicorn does not yet support hash instructions in A32.
|
||||
// CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SHA256H2.32 <Qd>, <Qn>, <Qm>")]
|
||||
public void Sha256h2_V([Values(0xF3100C40u)] uint opcode,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(2u)] uint rn,
|
||||
[Values(4u)] uint rm,
|
||||
[Values(0xAEE65C11943FB939ul)] ulong z0,
|
||||
[Values(0xA89A87F110291DA3ul)] ulong z1,
|
||||
[Values(0xE9F766DB7A49EA7Dul)] ulong a0,
|
||||
[Values(0x3053F46B0C2F3507ul)] ulong a1,
|
||||
[Values(0x6E86A473B9D4A778ul)] ulong b0,
|
||||
[Values(0x7BE4F9E638156BB1ul)] ulong b1,
|
||||
[Values(0x0A1177E9D9C9B611ul)] ulong resultL,
|
||||
[Values(0xF5A826404928A515ul)] ulong resultH)
|
||||
{
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z0, z1);
|
||||
V128 v1 = MakeVectorE0E1(a0, a1);
|
||||
V128 v2 = MakeVectorE0E1(b0, b1);
|
||||
|
||||
ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, runUnicorn: false);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
|
||||
// Unicorn does not yet support hash instructions in A32.
|
||||
// CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SHA256SU1.32 <Qd>, <Qn>, <Qm>")]
|
||||
public void Sha256su1_V([Values(0xF3200C40u)] uint opcode,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(2u)] uint rn,
|
||||
[Values(4u)] uint rm,
|
||||
[Values(0xAEE65C11943FB939ul)] ulong z0,
|
||||
[Values(0xA89A87F110291DA3ul)] ulong z1,
|
||||
[Values(0xE9F766DB7A49EA7Dul)] ulong a0,
|
||||
[Values(0x3053F46B0C2F3507ul)] ulong a1,
|
||||
[Values(0x6E86A473B9D4A778ul)] ulong b0,
|
||||
[Values(0x7BE4F9E638156BB1ul)] ulong b1,
|
||||
[Values(0x9EE69CC896D7DE66ul)] ulong resultL,
|
||||
[Values(0x004A147155573E54ul)] ulong resultH)
|
||||
{
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z0, z1);
|
||||
V128 v1 = MakeVectorE0E1(a0, a1);
|
||||
V128 v2 = MakeVectorE0E1(b0, b1);
|
||||
|
||||
ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, runUnicorn: false);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL));
|
||||
Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH));
|
||||
});
|
||||
|
||||
// Unicorn does not yet support hash instructions in A32.
|
||||
// CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise, Description("VADD.f32 V0, V0, V0")]
|
||||
public void Vadd_F32([Values(0u)] uint rd,
|
||||
[Values(0u, 1u)] uint rn,
|
||||
[Values(0u, 2u)] uint rm,
|
||||
[ValueSource(nameof(_2S_F_))] ulong z0,
|
||||
[ValueSource(nameof(_2S_F_))] ulong z1,
|
||||
[ValueSource(nameof(_2S_F_))] ulong a0,
|
||||
[ValueSource(nameof(_2S_F_))] ulong a1,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b0,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b1,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf2000d00u; // VADD.F32 D0, D0, D0
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
rm <<= 1;
|
||||
rn <<= 1;
|
||||
rd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z0, z1);
|
||||
V128 v1 = MakeVectorE0E1(a0, a1);
|
||||
V128 v2 = MakeVectorE0E1(b0, b1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void V_Add_Sub_Long_Wide_I([ValueSource(nameof(_V_Add_Sub_Long_Wide_I_))] uint opcode,
|
||||
[Range(0u, 5u)] uint rd,
|
||||
[Range(0u, 5u)] uint rn,
|
||||
[Range(0u, 5u)] uint rm,
|
||||
[ValueSource(nameof(_8B4H2S1D_))] ulong z,
|
||||
[ValueSource(nameof(_8B4H2S1D_))] ulong a,
|
||||
[ValueSource(nameof(_8B4H2S1D_))] ulong b,
|
||||
[Values(0u, 1u, 2u)] uint size, // <SU8, SU16, SU32>
|
||||
[Values] bool u) // <S, U>
|
||||
{
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
}
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
rn >>= 1; rn <<= 1;
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
opcode |= (size & 0x3) << 20;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
V128 v1 = MakeVectorE0E1(a, ~a);
|
||||
V128 v2 = MakeVectorE0E1(b, ~b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VCMP.f<size> Vd, Vm")]
|
||||
public void Vcmp([Values(2u, 3u)] uint size,
|
||||
[ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_1S_F_))] ulong b,
|
||||
[Values] bool e)
|
||||
{
|
||||
uint opcode = 0xeeb40840u;
|
||||
uint rm = 1;
|
||||
uint rd = 2;
|
||||
|
||||
if (size == 3)
|
||||
{
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||
}
|
||||
|
||||
opcode |= ((size & 3) << 8);
|
||||
if (e)
|
||||
{
|
||||
opcode |= 1 << 7;
|
||||
}
|
||||
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0(b);
|
||||
|
||||
int fpscr = (int)(TestContext.CurrentContext.Random.NextUInt(0xf) << 28);
|
||||
|
||||
SingleOpcode(opcode, v1: v1, v2: v2, fpscr: fpscr);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Nzcv);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void Vfma_Vfms_Vfnma_Vfnms_S_F32([ValueSource(nameof(_Vfma_Vfms_Vfnma_Vfnms_S_F32_))] uint opcode,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s0,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s1,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s2,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s3)
|
||||
{
|
||||
opcode |= (((rd & 0x1) << 22) | (rd & 0x1e) << 11);
|
||||
opcode |= (((rn & 0x1) << 7) | (rn & 0x1e) << 15);
|
||||
opcode |= (((rm & 0x1) << 5) | (rm & 0x1e) >> 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1E2E3((uint)s0, (uint)s1, (uint)s2, (uint)s3);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void Vfma_Vfms_Vfnma_Vfnms_S_F64([ValueSource(nameof(_Vfma_Vfms_Vfnma_Vfnms_S_F64_))] uint opcode,
|
||||
[Values(0u, 1u)] uint rd,
|
||||
[Values(0u, 1u)] uint rn,
|
||||
[Values(0u, 1u)] uint rm,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d0,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d1)
|
||||
{
|
||||
opcode |= (((rd & 0x10) << 18) | (rd & 0xf) << 12);
|
||||
opcode |= (((rn & 0x10) << 3) | (rn & 0xf) << 16);
|
||||
opcode |= (((rm & 0x10) << 1) | (rm & 0xf) << 0);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void Vfma_Vfms_V_F32([ValueSource(nameof(_Vfma_Vfms_V_F32_))] uint opcode,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_2S_F_))] ulong d0,
|
||||
[ValueSource(nameof(_2S_F_))] ulong d1,
|
||||
[ValueSource(nameof(_2S_F_))] ulong d2,
|
||||
[ValueSource(nameof(_2S_F_))] ulong d3,
|
||||
[Values] bool q)
|
||||
{
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
rn >>= 1; rn <<= 1;
|
||||
rm >>= 1; rm <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||
V128 v1 = MakeVectorE0E1(d2, d3);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void Vmla_Vmls_Vnmla_Vnmls_S_F32([ValueSource(nameof(_Vmla_Vmls_Vnmla_Vnmls_S_F32_))] uint opcode,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s0,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s1,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s2,
|
||||
[ValueSource(nameof(_1S_F_))] ulong s3)
|
||||
{
|
||||
opcode |= (((rd & 0x1) << 22) | (rd & 0x1e) << 11);
|
||||
opcode |= (((rn & 0x1) << 7) | (rn & 0x1e) << 15);
|
||||
opcode |= (((rm & 0x1) << 5) | (rm & 0x1e) >> 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1E2E3((uint)s0, (uint)s1, (uint)s2, (uint)s3);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void Vmla_Vmls_Vnmla_Vnmls_S_F64([ValueSource(nameof(_Vmla_Vmls_Vnmla_Vnmls_S_F64_))] uint opcode,
|
||||
[Values(0u, 1u)] uint rd,
|
||||
[Values(0u, 1u)] uint rn,
|
||||
[Values(0u, 1u)] uint rm,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d0,
|
||||
[ValueSource(nameof(_1D_F_))] ulong d1)
|
||||
{
|
||||
opcode |= (((rd & 0x10) << 18) | (rd & 0xf) << 12);
|
||||
opcode |= (((rn & 0x10) << 3) | (rn & 0xf) << 16);
|
||||
opcode |= (((rm & 0x10) << 1) | (rm & 0xf) << 0);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vmlal_Vmlsl_I([ValueSource(nameof(_Vmlal_Vmlsl_V_I_))] uint opcode,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool u)
|
||||
{
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
opcode |= size << 20;
|
||||
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
}
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMULL.<size> <Vd>, <Vn>, <Vm>")]
|
||||
public void Vmull_I([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool op,
|
||||
[Values] bool u)
|
||||
{
|
||||
uint opcode = 0xf2800c00u; // VMULL.S8 Q0, D0, D0
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
if (op)
|
||||
{
|
||||
opcode |= 1 << 9;
|
||||
size = 0;
|
||||
u = false;
|
||||
}
|
||||
|
||||
opcode |= size << 20;
|
||||
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
}
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMULL.<P8, P64> <Qd>, <Dn>, <Dm>")]
|
||||
public void Vmull_I_P8_P64([Values(0u, 1u)] uint rd,
|
||||
[Values(0u, 1u)] uint rn,
|
||||
[Values(0u, 1u)] uint rm,
|
||||
[ValueSource(nameof(_8B1D_))] ulong d0,
|
||||
[ValueSource(nameof(_8B1D_))] ulong d1,
|
||||
[Values(0u/*, 2u*/)] uint size) // <P8, P64>
|
||||
{
|
||||
/*if (size == 2u)
|
||||
{
|
||||
Assert.Ignore("Ryujinx.Tests.Unicorn.UnicornException : Invalid instruction (UC_ERR_INSN_INVALID)");
|
||||
}*/
|
||||
|
||||
uint opcode = 0xf2800e00u; // VMULL.P8 Q0, D0, D0
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
|
||||
opcode |= (((rd & 0x10) << 18) | (rd & 0xf) << 12);
|
||||
opcode |= (((rn & 0x10) << 3) | (rn & 0xf) << 16);
|
||||
opcode |= (((rm & 0x10) << 1) | (rm & 0xf) << 0);
|
||||
|
||||
opcode |= (size & 0x3) << 20;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VSHL.<size> {<Vd>}, <Vm>, <Vn>")]
|
||||
public void Vshl([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint size,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool q,
|
||||
[Values] bool u)
|
||||
{
|
||||
uint opcode = 0xf2000400u; // VSHL.S8 D0, D0, D0
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
rm <<= 1;
|
||||
rn <<= 1;
|
||||
rd <<= 1;
|
||||
}
|
||||
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
}
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
opcode |= size << 20;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Explicit]
|
||||
[Test, Pairwise]
|
||||
public void Vp_Add_Max_Min_F([ValueSource(nameof(_Vp_Add_Max_Min_F_))] uint opcode,
|
||||
[Values(0u)] uint rd,
|
||||
[Range(0u, 7u)] uint rn,
|
||||
[Range(0u, 7u)] uint rm,
|
||||
[ValueSource(nameof(_2S_F_))] ulong z0,
|
||||
[ValueSource(nameof(_2S_F_))] ulong z1,
|
||||
[ValueSource(nameof(_2S_F_))] ulong a0,
|
||||
[ValueSource(nameof(_2S_F_))] ulong a1,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b0,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b1)
|
||||
{
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z0, z1);
|
||||
V128 v1 = MakeVectorE0E1(a0, a1);
|
||||
V128 v2 = MakeVectorE0E1(b0, b1);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vp_Add_I([ValueSource(nameof(_Vp_Add_I_))] uint opcode,
|
||||
[Values(0u)] uint rd,
|
||||
[Range(0u, 5u)] uint rn,
|
||||
[Range(0u, 5u)] uint rm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b)
|
||||
{
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
opcode |= size << 20;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void V_Pmax_Pmin_Rhadd_I([ValueSource(nameof(_V_Pmax_Pmin_Rhadd_I_))] uint opcode,
|
||||
[Values(0u)] uint rd,
|
||||
[Range(0u, 5u)] uint rn,
|
||||
[Range(0u, 5u)] uint rm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool u)
|
||||
{
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
}
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
opcode |= size << 20;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vq_Add_Sub_I([ValueSource(nameof(_Vq_Add_Sub_I_))] uint opcode,
|
||||
[Range(0u, 5u)] uint rd,
|
||||
[Range(0u, 5u)] uint rn,
|
||||
[Range(0u, 5u)] uint rm,
|
||||
[ValueSource(nameof(_8B4H2S1D_))] ulong z,
|
||||
[ValueSource(nameof(_8B4H2S1D_))] ulong a,
|
||||
[ValueSource(nameof(_8B4H2S1D_))] ulong b,
|
||||
[Values(0u, 1u, 2u)] uint size, // <SU8, SU16, SU32>
|
||||
[Values] bool u) // <S, U>
|
||||
{
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
}
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
rn >>= 1; rn <<= 1;
|
||||
rm >>= 1; rm <<= 1;
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
opcode |= (size & 0x3) << 20;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
V128 v1 = MakeVectorE0E1(a, ~a);
|
||||
V128 v2 = MakeVectorE0E1(b, ~b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VQDMULH.<S16, S32> <Qd>, <Qn>, <Qm>")]
|
||||
public void Vqdmulh_I([Range(0u, 5u)] uint rd,
|
||||
[Range(0u, 5u)] uint rn,
|
||||
[Range(0u, 5u)] uint rm,
|
||||
[ValueSource(nameof(_8B4H2S1D_))] ulong z,
|
||||
[ValueSource(nameof(_8B4H2S1D_))] ulong a,
|
||||
[ValueSource(nameof(_8B4H2S1D_))] ulong b,
|
||||
[Values(1u, 2u)] uint size) // <S16, S32>
|
||||
{
|
||||
rd >>= 1; rd <<= 1;
|
||||
rn >>= 1; rn <<= 1;
|
||||
rm >>= 1; rm <<= 1;
|
||||
|
||||
uint opcode = 0xf2100b40u & ~(3u << 20); // VQDMULH.S16 Q0, Q0, Q0
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
opcode |= (size & 0x3) << 20;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
V128 v1 = MakeVectorE0E1(a, ~a);
|
||||
V128 v2 = MakeVectorE0E1(b, ~b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
191
src/Ryujinx.Tests/Cpu/CpuTestSimdRegElem.cs
Normal file
191
src/Ryujinx.Tests/Cpu/CpuTestSimdRegElem.cs
Normal file
|
@ -0,0 +1,191 @@
|
|||
#define SimdRegElem
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdRegElem")]
|
||||
public sealed class CpuTestSimdRegElem : CpuTest
|
||||
{
|
||||
#if SimdRegElem
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _2S_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _4H_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Mla_Mls_Mul_Sqdmulh_Sqrdmulh_Ve_4H_8H_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x2F400000u, // MLA V0.4H, V0.4H, V0.H[0]
|
||||
0x2F404000u, // MLS V0.4H, V0.4H, V0.H[0]
|
||||
0x0F408000u, // MUL V0.4H, V0.4H, V0.H[0]
|
||||
0x0F40C000u, // SQDMULH V0.4H, V0.4H, V0.H[0]
|
||||
0x0F40D000u // SQRDMULH V0.4H, V0.4H, V0.H[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Mla_Mls_Mul_Sqdmulh_Sqrdmulh_Ve_2S_4S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x2F800000u, // MLA V0.2S, V0.2S, V0.S[0]
|
||||
0x2F804000u, // MLS V0.2S, V0.2S, V0.S[0]
|
||||
0x0F808000u, // MUL V0.2S, V0.2S, V0.S[0]
|
||||
0x0F80C000u, // SQDMULH V0.2S, V0.2S, V0.S[0]
|
||||
0x0F80D000u // SQRDMULH V0.2S, V0.2S, V0.S[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Mlal_Mlsl_Mull_Ve_4H4S_8H4S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0F402000u, // SMLAL V0.4S, V0.4H, V0.H[0]
|
||||
0x0F406000u, // SMLSL V0.4S, V0.4H, V0.H[0]
|
||||
0x0F40A000u, // SMULL V0.4S, V0.4H, V0.H[0]
|
||||
0x2F402000u, // UMLAL V0.4S, V0.4H, V0.H[0]
|
||||
0x2F406000u, // UMLSL V0.4S, V0.4H, V0.H[0]
|
||||
0x2F40A000u // UMULL V0.4S, V0.4H, V0.H[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _SU_Mlal_Mlsl_Mull_Ve_2S2D_4S2D_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0F802000u, // SMLAL V0.2D, V0.2S, V0.S[0]
|
||||
0x0F806000u, // SMLSL V0.2D, V0.2S, V0.S[0]
|
||||
0x0F80A000u, // SMULL V0.2D, V0.2S, V0.S[0]
|
||||
0x2F802000u, // UMLAL V0.2D, V0.2S, V0.S[0]
|
||||
0x2F806000u, // UMLSL V0.2D, V0.2S, V0.S[0]
|
||||
0x2F80A000u // UMULL V0.2D, V0.2S, V0.S[0]
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Mla_Mls_Mul_Sqdmulh_Sqrdmulh_Ve_4H_8H([ValueSource(nameof(_Mla_Mls_Mul_Sqdmulh_Sqrdmulh_Ve_4H_8H_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[ValueSource(nameof(_4H_))] ulong b,
|
||||
[Values(0u, 7u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <4H, 8H>
|
||||
{
|
||||
uint h = (index >> 2) & 1;
|
||||
uint l = (index >> 1) & 1;
|
||||
uint m = index & 1;
|
||||
|
||||
opcodes |= ((rm & 15) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (l << 21) | (m << 20) | (h << 11);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a * q);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Qc);
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Mla_Mls_Mul_Sqdmulh_Sqrdmulh_Ve_2S_4S([ValueSource(nameof(_Mla_Mls_Mul_Sqdmulh_Sqrdmulh_Ve_2S_4S_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[ValueSource(nameof(_2S_))] ulong b,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
uint h = (index >> 1) & 1;
|
||||
uint l = index & 1;
|
||||
|
||||
opcodes |= ((rm & 15) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (l << 21) | (h << 11);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a * q);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Qc);
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void SU_Mlal_Mlsl_Mull_Ve_4H4S_8H4S([ValueSource(nameof(_SU_Mlal_Mlsl_Mull_Ve_4H4S_8H4S_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_4H_))] ulong a,
|
||||
[ValueSource(nameof(_4H_))] ulong b,
|
||||
[Values(0u, 7u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <4H4S, 8H4S>
|
||||
{
|
||||
uint h = (index >> 2) & 1;
|
||||
uint l = (index >> 1) & 1;
|
||||
uint m = index & 1;
|
||||
|
||||
opcodes |= ((rm & 15) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (l << 21) | (m << 20) | (h << 11);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void SU_Mlal_Mlsl_Mull_Ve_2S2D_4S2D([ValueSource(nameof(_SU_Mlal_Mlsl_Mull_Ve_2S2D_4S2D_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_2S_))] ulong a,
|
||||
[ValueSource(nameof(_2S_))] ulong b,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S2D, 4S2D>
|
||||
{
|
||||
uint h = (index >> 1) & 1;
|
||||
uint l = index & 1;
|
||||
|
||||
opcodes |= ((rm & 15) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (l << 21) | (h << 11);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
80
src/Ryujinx.Tests/Cpu/CpuTestSimdRegElem32.cs
Normal file
80
src/Ryujinx.Tests/Cpu/CpuTestSimdRegElem32.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
#define SimdRegElem32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdRegElem32")]
|
||||
public sealed class CpuTestSimdRegElem32 : CpuTest32
|
||||
{
|
||||
#if SimdRegElem32
|
||||
private const int RndCnt = 2;
|
||||
|
||||
[Test, Pairwise, Description("VMUL.<size> {<Vd>}, <Vn>, <Vm>[<index>]")]
|
||||
public void Vmul_1I([Values(1u, 0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(26u, 25u, 10u, 9u, 2u, 0u)] uint rm,
|
||||
[Values(1u, 2u)] uint size,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf2900840u & ~(3u << 20); // VMUL.I16 D0, D0, D0[0]
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
rn <<= 1;
|
||||
rd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
opcode |= size << 20;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VMULL.<size> <Vd>, <Vn>, <Vm>[<index>]")]
|
||||
public void Vmull_1([Values(2u, 0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(26u, 25u, 10u, 9u, 2u, 0u)] uint rm,
|
||||
[Values(1u, 2u)] uint size,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool u)
|
||||
{
|
||||
uint opcode = 0xf2900a40u & ~(3u << 20); // VMULL.S16 Q0, D0, D0[0]
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
opcode |= size << 20;
|
||||
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
}
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
445
src/Ryujinx.Tests/Cpu/CpuTestSimdRegElemF.cs
Normal file
445
src/Ryujinx.Tests/Cpu/CpuTestSimdRegElemF.cs
Normal file
|
@ -0,0 +1,445 @@
|
|||
#define SimdRegElemF
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdRegElemF")]
|
||||
public sealed class CpuTestSimdRegElemF : CpuTest
|
||||
{
|
||||
#if SimdRegElemF
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static IEnumerable<ulong> _1S_F_()
|
||||
{
|
||||
yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x0000000080800000ul; // -Min Normal
|
||||
yield return 0x00000000807FFFFFul; // -Max Subnormal
|
||||
yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0000000000800000ul; // +Min Normal
|
||||
yield return 0x00000000007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x0000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0x00000000FF800000ul; // -Infinity
|
||||
yield return 0x000000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong grbg = TestContext.CurrentContext.Random.NextUInt();
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (grbg << 32) | rnd1;
|
||||
yield return (grbg << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _2S_F_()
|
||||
{
|
||||
yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue)
|
||||
yield return 0x8080000080800000ul; // -Min Normal
|
||||
yield return 0x807FFFFF807FFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon)
|
||||
yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue)
|
||||
yield return 0x0080000000800000ul; // +Min Normal
|
||||
yield return 0x007FFFFF007FFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000080000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFF800000FF800000ul; // -Infinity
|
||||
yield return 0x7F8000007F800000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN)
|
||||
yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||
yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalS();
|
||||
ulong rnd2 = GenSubnormalS();
|
||||
|
||||
yield return (rnd1 << 32) | rnd1;
|
||||
yield return (rnd2 << 32) | rnd2;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _1D_F_()
|
||||
{
|
||||
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
||||
yield return 0x8010000000000000ul; // -Min Normal
|
||||
yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
|
||||
yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
|
||||
yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
|
||||
yield return 0x0010000000000000ul; // +Min Normal
|
||||
yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
|
||||
yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
|
||||
|
||||
if (!NoZeros)
|
||||
{
|
||||
yield return 0x8000000000000000ul; // -Zero
|
||||
yield return 0x0000000000000000ul; // +Zero
|
||||
}
|
||||
|
||||
if (!NoInfs)
|
||||
{
|
||||
yield return 0xFFF0000000000000ul; // -Infinity
|
||||
yield return 0x7FF0000000000000ul; // +Infinity
|
||||
}
|
||||
|
||||
if (!NoNaNs)
|
||||
{
|
||||
yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
|
||||
yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
|
||||
yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
|
||||
yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
|
||||
}
|
||||
|
||||
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||
{
|
||||
ulong rnd1 = GenNormalD();
|
||||
ulong rnd2 = GenSubnormalD();
|
||||
|
||||
yield return rnd1;
|
||||
yield return rnd2;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _F_Mla_Mls_Se_S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x5F821020u, // FMLA S0, S1, V2.S[0]
|
||||
0x5F825020u // FMLS S0, S1, V2.S[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mla_Mls_Se_D_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x5FC21020u, // FMLA D0, D1, V2.D[0]
|
||||
0x5FC25020u // FMLS D0, D1, V2.D[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mla_Mls_Ve_2S_4S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0F801000u, // FMLA V0.2S, V0.2S, V0.S[0]
|
||||
0x0F805000u // FMLS V0.2S, V0.2S, V0.S[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mla_Mls_Ve_2D_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x4FC01000u, // FMLA V0.2D, V0.2D, V0.D[0]
|
||||
0x4FC05000u // FMLS V0.2D, V0.2D, V0.D[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mul_Mulx_Se_S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x5F829020u, // FMUL S0, S1, V2.S[0]
|
||||
0x7F829020u // FMULX S0, S1, V2.S[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mul_Mulx_Se_D_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x5FC29020u, // FMUL D0, D1, V2.D[0]
|
||||
0x7FC29020u // FMULX D0, D1, V2.D[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mul_Mulx_Ve_2S_4S_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0F809000u, // FMUL V0.2S, V0.2S, V0.S[0]
|
||||
0x2F809000u // FMULX V0.2S, V0.2S, V0.S[0]
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _F_Mul_Mulx_Ve_2D_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x4FC09000u, // FMUL V0.2D, V0.2D, V0.D[0]
|
||||
0x6FC09000u // FMULX V0.2D, V0.2D, V0.D[0]
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
|
||||
private static readonly bool NoZeros = false;
|
||||
private static readonly bool NoInfs = false;
|
||||
private static readonly bool NoNaNs = false;
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void F_Mla_Mls_Se_S([ValueSource(nameof(_F_Mla_Mls_Se_S_))] uint opcodes,
|
||||
[ValueSource(nameof(_1S_F_))] ulong z,
|
||||
[ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
uint h = (index >> 1) & 1;
|
||||
uint l = index & 1;
|
||||
|
||||
opcodes |= (l << 21) | (h << 11);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(Fpsr.Ioc | Fpsr.Idc, FpSkips.IfUnderflow, FpTolerances.UpToOneUlpsS);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void F_Mla_Mls_Se_D([ValueSource(nameof(_F_Mla_Mls_Se_D_))] uint opcodes,
|
||||
[ValueSource(nameof(_1D_F_))] ulong z,
|
||||
[ValueSource(nameof(_1D_F_))] ulong a,
|
||||
[ValueSource(nameof(_1D_F_))] ulong b,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
uint h = index & 1;
|
||||
|
||||
opcodes |= h << 11;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(Fpsr.Ioc | Fpsr.Idc, FpSkips.IfUnderflow, FpTolerances.UpToOneUlpsD);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void F_Mla_Mls_Ve_2S_4S([ValueSource(nameof(_F_Mla_Mls_Ve_2S_4S_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_2S_F_))] ulong z,
|
||||
[ValueSource(nameof(_2S_F_))] ulong a,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
uint h = (index >> 1) & 1;
|
||||
uint l = index & 1;
|
||||
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (l << 21) | (h << 11);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a * q);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(Fpsr.Ioc | Fpsr.Idc, FpSkips.IfUnderflow, FpTolerances.UpToOneUlpsS);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit] // Fused.
|
||||
public void F_Mla_Mls_Ve_2D([ValueSource(nameof(_F_Mla_Mls_Ve_2D_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_1D_F_))] ulong z,
|
||||
[ValueSource(nameof(_1D_F_))] ulong a,
|
||||
[ValueSource(nameof(_1D_F_))] ulong b,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
uint h = index & 1;
|
||||
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= h << 11;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(Fpsr.Ioc | Fpsr.Idc, FpSkips.IfUnderflow, FpTolerances.UpToOneUlpsD);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mul_Mulx_Se_S([ValueSource(nameof(_F_Mul_Mulx_Se_S_))] uint opcodes,
|
||||
[ValueSource(nameof(_1S_F_))] ulong a,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index)
|
||||
{
|
||||
uint h = (index >> 1) & 1;
|
||||
uint l = index & 1;
|
||||
|
||||
opcodes |= (l << 21) | (h << 11);
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc | Fpsr.Idc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mul_Mulx_Se_D([ValueSource(nameof(_F_Mul_Mulx_Se_D_))] uint opcodes,
|
||||
[ValueSource(nameof(_1D_F_))] ulong a,
|
||||
[ValueSource(nameof(_1D_F_))] ulong b,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
uint h = index & 1;
|
||||
|
||||
opcodes |= h << 11;
|
||||
|
||||
ulong z = TestContext.CurrentContext.Random.NextULong();
|
||||
V128 v0 = MakeVectorE1(z);
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc | Fpsr.Idc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mul_Mulx_Ve_2S_4S([ValueSource(nameof(_F_Mul_Mulx_Ve_2S_4S_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_2S_F_))] ulong z,
|
||||
[ValueSource(nameof(_2S_F_))] ulong a,
|
||||
[ValueSource(nameof(_2S_F_))] ulong b,
|
||||
[Values(0u, 1u, 2u, 3u)] uint index,
|
||||
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||
{
|
||||
uint h = (index >> 1) & 1;
|
||||
uint l = index & 1;
|
||||
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= (l << 21) | (h << 11);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a * q);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc | Fpsr.Idc);
|
||||
}
|
||||
|
||||
[Test, Pairwise] [Explicit]
|
||||
public void F_Mul_Mulx_Ve_2D([ValueSource(nameof(_F_Mul_Mulx_Ve_2D_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[ValueSource(nameof(_1D_F_))] ulong z,
|
||||
[ValueSource(nameof(_1D_F_))] ulong a,
|
||||
[ValueSource(nameof(_1D_F_))] ulong b,
|
||||
[Values(0u, 1u)] uint index)
|
||||
{
|
||||
uint h = index & 1;
|
||||
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= h << 11;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, a);
|
||||
V128 v2 = MakeVectorE0E1(b, b * h);
|
||||
|
||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||
|
||||
int fpcr = rnd & (1 << (int)Fpcr.Fz);
|
||||
fpcr |= rnd & (1 << (int)Fpcr.Dn);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, fpcr: fpcr);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Ioc | Fpsr.Idc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
1111
src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs
Normal file
1111
src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs
Normal file
File diff suppressed because it is too large
Load diff
315
src/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs
Normal file
315
src/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs
Normal file
|
@ -0,0 +1,315 @@
|
|||
#define SimdShImm32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdShImm32")]
|
||||
public sealed class CpuTestSimdShImm32 : CpuTest32
|
||||
{
|
||||
#if SimdShImm32
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _1D_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _2S_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFFFFFF7FFFFFFFul, 0x8000000080000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _4H_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul, 0x8000800080008000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful, 0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _Vshr_Imm_SU8_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2880010u, // VSHR.S8 D0, D0, #8
|
||||
0xf2880110u, // VSRA.S8 D0, D0, #8
|
||||
0xf2880210u, // VRSHR.S8 D0, D0, #8
|
||||
0xf2880310u // VRSRA.S8 D0, D0, #8
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vshr_Imm_SU16_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2900010u, // VSHR.S16 D0, D0, #16
|
||||
0xf2900110u, // VSRA.S16 D0, D0, #16
|
||||
0xf2900210u, // VRSHR.S16 D0, D0, #16
|
||||
0xf2900310u // VRSRA.S16 D0, D0, #16
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vshr_Imm_SU32_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2a00010u, // VSHR.S32 D0, D0, #32
|
||||
0xf2a00110u, // VSRA.S32 D0, D0, #32
|
||||
0xf2a00210u, // VRSHR.S32 D0, D0, #32
|
||||
0xf2a00310u // VRSRA.S32 D0, D0, #32
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vshr_Imm_SU64_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2800190u, // VSRA.S64 D0, D0, #64
|
||||
0xf2800290u, // VRSHR.S64 D0, D0, #64
|
||||
0xf2800090u // VSHR.S64 D0, D0, #64
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vqshrn_Vqrshrn_Vrshrn_Imm_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf2800910u, // VORR.I16 D0, #0 (immediate value changes it into QSHRN)
|
||||
0xf2800950u, // VORR.I16 Q0, #0 (immediate value changes it into QRSHRN)
|
||||
0xf2800850u // VMOV.I16 Q0, #0 (immediate value changes it into RSHRN)
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _Vqshrun_Vqrshrun_Imm_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xf3800810u, // VMOV.I16 D0, #0x80 (immediate value changes it into QSHRUN)
|
||||
0xf3800850u // VMOV.I16 Q0, #0x80 (immediate value changes it into QRSHRUN)
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCnt = 2;
|
||||
private const int RndCntShiftImm = 2;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vshr_Imm_SU8([ValueSource(nameof(_Vshr_Imm_SU8_))] uint opcode,
|
||||
[Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong b,
|
||||
[Values(1u, 8u)] uint shiftImm,
|
||||
[Values] bool u,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint imm6 = 16 - shiftImm;
|
||||
|
||||
Vshr_Imm_SU(opcode, rd, rm, z, b, imm6, u, q);
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vshr_Imm_SU16([ValueSource(nameof(_Vshr_Imm_SU16_))] uint opcode,
|
||||
[Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_4H_))] ulong z,
|
||||
[ValueSource(nameof(_4H_))] ulong b,
|
||||
[Values(1u, 16u)] uint shiftImm,
|
||||
[Values] bool u,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint imm6 = 32 - shiftImm;
|
||||
|
||||
Vshr_Imm_SU(opcode, rd, rm, z, b, imm6, u, q);
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vshr_Imm_SU32([ValueSource(nameof(_Vshr_Imm_SU32_))] uint opcode,
|
||||
[Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_2S_))] ulong z,
|
||||
[ValueSource(nameof(_2S_))] ulong b,
|
||||
[Values(1u, 32u)] uint shiftImm,
|
||||
[Values] bool u,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint imm6 = 64 - shiftImm;
|
||||
|
||||
Vshr_Imm_SU(opcode, rd, rm, z, b, imm6, u, q);
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vshr_Imm_SU64([ValueSource(nameof(_Vshr_Imm_SU64_))] uint opcode,
|
||||
[Range(0u, 3u)] uint rd,
|
||||
[Range(0u, 3u)] uint rm,
|
||||
[ValueSource(nameof(_1D_))] ulong z,
|
||||
[ValueSource(nameof(_1D_))] ulong b,
|
||||
[Values(1u, 64u)] uint shiftImm,
|
||||
[Values] bool u,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint imm6 = 64 - shiftImm;
|
||||
|
||||
Vshr_Imm_SU(opcode, rd, rm, z, b, imm6, u, q);
|
||||
}
|
||||
|
||||
private void Vshr_Imm_SU(uint opcode, uint rd, uint rm, ulong z, ulong b, uint imm6, bool u, bool q)
|
||||
{
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1 << 24;
|
||||
}
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
|
||||
rd >>= 1; rd <<= 1;
|
||||
rm >>= 1; rm <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
|
||||
opcode |= (imm6 & 0x3f) << 16;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, ~z);
|
||||
V128 v1 = MakeVectorE0E1(b, ~b);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VSHL.<size> {<Vd>}, <Vm>, #<imm>")]
|
||||
public void Vshl_Imm([Values(0u)] uint rd,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint size,
|
||||
[Random(RndCntShiftImm)] uint shiftImm,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf2800510u; // VORR.I32 D0, #0 (immediate value changes it into SHL)
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
rm <<= 1;
|
||||
rd <<= 1;
|
||||
}
|
||||
|
||||
uint imm = 1u << ((int)size + 3);
|
||||
imm |= shiftImm & (imm - 1);
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((imm & 0x3f) << 16) | ((imm & 0x40) << 1);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VSHRN.<size> <Vd>, <Vm>, #<imm>")]
|
||||
public void Vshrn_Imm([Values(0u, 1u)] uint rd,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCntShiftImm)] uint shiftImm,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b)
|
||||
{
|
||||
uint opcode = 0xf2800810u; // VMOV.I16 D0, #0 (immediate value changes it into SHRN)
|
||||
|
||||
uint imm = 1u << ((int)size + 3);
|
||||
imm |= shiftImm & (imm - 1);
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((imm & 0x3f) << 16);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vqshrn_Vqrshrn_Vrshrn_Imm([ValueSource(nameof(_Vqshrn_Vqrshrn_Vrshrn_Imm_))] uint opcode,
|
||||
[Values(0u, 1u)] uint rd,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCntShiftImm)] uint shiftImm,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool u)
|
||||
{
|
||||
uint imm = 1u << ((int)size + 3);
|
||||
imm |= shiftImm & (imm - 1);
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((imm & 0x3f) << 16);
|
||||
|
||||
if (u)
|
||||
{
|
||||
opcode |= 1u << 24;
|
||||
}
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
int fpscr = (int)TestContext.CurrentContext.Random.NextUInt() & (int)Fpsr.Qc;
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Qc);
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Vqshrun_Vqrshrun_Imm([ValueSource(nameof(_Vqshrun_Vqrshrun_Imm_))] uint opcode,
|
||||
[Values(0u, 1u)] uint rd,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCntShiftImm)] uint shiftImm,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b)
|
||||
{
|
||||
uint imm = 1u << ((int)size + 3);
|
||||
imm |= shiftImm & (imm - 1);
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((imm & 0x3f) << 16);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
int fpscr = (int)TestContext.CurrentContext.Random.NextUInt() & (int)Fpsr.Qc;
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr);
|
||||
|
||||
CompareAgainstUnicorn(fpsrMask: Fpsr.Qc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
317
src/Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs
Normal file
317
src/Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs
Normal file
|
@ -0,0 +1,317 @@
|
|||
#define SimdTbl
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdTbl")]
|
||||
public sealed class CpuTestSimdTbl : CpuTest
|
||||
{
|
||||
#if SimdTbl
|
||||
|
||||
#region "Helper methods"
|
||||
private static ulong GenIdxsForTbls(int regs)
|
||||
{
|
||||
const byte idxInRngMin = 0;
|
||||
byte idxInRngMax = (byte)((16 * regs) - 1);
|
||||
byte idxOutRngMin = (byte) (16 * regs);
|
||||
const byte idxOutRngMax = 255;
|
||||
|
||||
ulong idxs = 0ul;
|
||||
|
||||
for (int cnt = 1; cnt <= 8; cnt++)
|
||||
{
|
||||
ulong idxInRng = TestContext.CurrentContext.Random.NextByte(idxInRngMin, idxInRngMax);
|
||||
ulong idxOutRng = TestContext.CurrentContext.Random.NextByte(idxOutRngMin, idxOutRngMax);
|
||||
|
||||
ulong idx = TestContext.CurrentContext.Random.NextBool() ? idxInRng : idxOutRng;
|
||||
|
||||
idxs = (idxs << 8) | idx;
|
||||
}
|
||||
|
||||
return idxs;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static ulong[] _8B_()
|
||||
{
|
||||
return new[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _GenIdxsForTbl1_()
|
||||
{
|
||||
yield return 0x0000000000000000ul;
|
||||
yield return 0x7F7F7F7F7F7F7F7Ful;
|
||||
yield return 0x8080808080808080ul;
|
||||
yield return 0xFFFFFFFFFFFFFFFFul;
|
||||
|
||||
for (int cnt = 1; cnt <= RndCntIdxs; cnt++)
|
||||
{
|
||||
yield return GenIdxsForTbls(regs: 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _GenIdxsForTbl2_()
|
||||
{
|
||||
yield return 0x0000000000000000ul;
|
||||
yield return 0x7F7F7F7F7F7F7F7Ful;
|
||||
yield return 0x8080808080808080ul;
|
||||
yield return 0xFFFFFFFFFFFFFFFFul;
|
||||
|
||||
for (int cnt = 1; cnt <= RndCntIdxs; cnt++)
|
||||
{
|
||||
yield return GenIdxsForTbls(regs: 2);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _GenIdxsForTbl3_()
|
||||
{
|
||||
yield return 0x0000000000000000ul;
|
||||
yield return 0x7F7F7F7F7F7F7F7Ful;
|
||||
yield return 0x8080808080808080ul;
|
||||
yield return 0xFFFFFFFFFFFFFFFFul;
|
||||
|
||||
for (int cnt = 1; cnt <= RndCntIdxs; cnt++)
|
||||
{
|
||||
yield return GenIdxsForTbls(regs: 3);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ulong> _GenIdxsForTbl4_()
|
||||
{
|
||||
yield return 0x0000000000000000ul;
|
||||
yield return 0x7F7F7F7F7F7F7F7Ful;
|
||||
yield return 0x8080808080808080ul;
|
||||
yield return 0xFFFFFFFFFFFFFFFFul;
|
||||
|
||||
for (int cnt = 1; cnt <= RndCntIdxs; cnt++)
|
||||
{
|
||||
yield return GenIdxsForTbls(regs: 4);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _SingleRegisterTable_V_8B_16B_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0E000000u, // TBL V0.8B, { V0.16B }, V0.8B
|
||||
0x0E001000u // TBX V0.8B, { V0.16B }, V0.8B
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _TwoRegisterTable_V_8B_16B_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0E002000u, // TBL V0.8B, { V0.16B, V1.16B }, V0.8B
|
||||
0x0E003000u // TBX V0.8B, { V0.16B, V1.16B }, V0.8B
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _ThreeRegisterTable_V_8B_16B_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0E004000u, // TBL V0.8B, { V0.16B, V1.16B, V2.16B }, V0.8B
|
||||
0x0E005000u // TBX V0.8B, { V0.16B, V1.16B, V2.16B }, V0.8B
|
||||
};
|
||||
}
|
||||
|
||||
private static uint[] _FourRegisterTable_V_8B_16B_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0x0E006000u, // TBL V0.8B, { V0.16B, V1.16B, V2.16B, V3.16B }, V0.8B
|
||||
0x0E006000u // TBX V0.8B, { V0.16B, V1.16B, V2.16B, V3.16B }, V0.8B
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
private const int RndCntIdxs = 2;
|
||||
|
||||
[Test, Pairwise]
|
||||
public void SingleRegisterTable_V_8B_16B([ValueSource(nameof(_SingleRegisterTable_V_8B_16B_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[Values(2u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong table0,
|
||||
[ValueSource(nameof(_GenIdxsForTbl1_))] ulong indexes,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(table0, table0);
|
||||
V128 v2 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void TwoRegisterTable_V_8B_16B([ValueSource(nameof(_TwoRegisterTable_V_8B_16B_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[Values(3u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong table0,
|
||||
[ValueSource(nameof(_8B_))] ulong table1,
|
||||
[ValueSource(nameof(_GenIdxsForTbl2_))] ulong indexes,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(table0, table0);
|
||||
V128 v2 = MakeVectorE0E1(table1, table1);
|
||||
V128 v3 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Mod_TwoRegisterTable_V_8B_16B([ValueSource(nameof(_TwoRegisterTable_V_8B_16B_))] uint opcodes,
|
||||
[Values(30u, 1u)] uint rd,
|
||||
[Values(31u)] uint rn,
|
||||
[Values(1u, 30u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong table0,
|
||||
[ValueSource(nameof(_8B_))] ulong table1,
|
||||
[ValueSource(nameof(_GenIdxsForTbl2_))] ulong indexes,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v30 = MakeVectorE0E1(z, z);
|
||||
V128 v31 = MakeVectorE0E1(table0, table0);
|
||||
V128 v0 = MakeVectorE0E1(table1, table1);
|
||||
V128 v1 = MakeVectorE0E1(indexes, indexes);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v30: v30, v31: v31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void ThreeRegisterTable_V_8B_16B([ValueSource(nameof(_ThreeRegisterTable_V_8B_16B_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[Values(4u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong table0,
|
||||
[ValueSource(nameof(_8B_))] ulong table1,
|
||||
[ValueSource(nameof(_8B_))] ulong table2,
|
||||
[ValueSource(nameof(_GenIdxsForTbl3_))] ulong indexes,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(table0, table0);
|
||||
V128 v2 = MakeVectorE0E1(table1, table1);
|
||||
V128 v3 = MakeVectorE0E1(table2, table2);
|
||||
V128 v4 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3, v4: v4);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Mod_ThreeRegisterTable_V_8B_16B([ValueSource(nameof(_ThreeRegisterTable_V_8B_16B_))] uint opcodes,
|
||||
[Values(30u, 2u)] uint rd,
|
||||
[Values(31u)] uint rn,
|
||||
[Values(2u, 30u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong table0,
|
||||
[ValueSource(nameof(_8B_))] ulong table1,
|
||||
[ValueSource(nameof(_8B_))] ulong table2,
|
||||
[ValueSource(nameof(_GenIdxsForTbl3_))] ulong indexes,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v30 = MakeVectorE0E1(z, z);
|
||||
V128 v31 = MakeVectorE0E1(table0, table0);
|
||||
V128 v0 = MakeVectorE0E1(table1, table1);
|
||||
V128 v1 = MakeVectorE0E1(table2, table2);
|
||||
V128 v2 = MakeVectorE0E1(indexes, indexes);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v30: v30, v31: v31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void FourRegisterTable_V_8B_16B([ValueSource(nameof(_FourRegisterTable_V_8B_16B_))] uint opcodes,
|
||||
[Values(0u)] uint rd,
|
||||
[Values(1u)] uint rn,
|
||||
[Values(5u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong table0,
|
||||
[ValueSource(nameof(_8B_))] ulong table1,
|
||||
[ValueSource(nameof(_8B_))] ulong table2,
|
||||
[ValueSource(nameof(_8B_))] ulong table3,
|
||||
[ValueSource(nameof(_GenIdxsForTbl4_))] ulong indexes,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(table0, table0);
|
||||
V128 v2 = MakeVectorE0E1(table1, table1);
|
||||
V128 v3 = MakeVectorE0E1(table2, table2);
|
||||
V128 v4 = MakeVectorE0E1(table3, table3);
|
||||
V128 v5 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3, v4: v4, v5: v5);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise]
|
||||
public void Mod_FourRegisterTable_V_8B_16B([ValueSource(nameof(_FourRegisterTable_V_8B_16B_))] uint opcodes,
|
||||
[Values(30u, 3u)] uint rd,
|
||||
[Values(31u)] uint rn,
|
||||
[Values(3u, 30u)] uint rm,
|
||||
[ValueSource(nameof(_8B_))] ulong z,
|
||||
[ValueSource(nameof(_8B_))] ulong table0,
|
||||
[ValueSource(nameof(_8B_))] ulong table1,
|
||||
[ValueSource(nameof(_8B_))] ulong table2,
|
||||
[ValueSource(nameof(_8B_))] ulong table3,
|
||||
[ValueSource(nameof(_GenIdxsForTbl4_))] ulong indexes,
|
||||
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||
{
|
||||
opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||
opcodes |= ((q & 1) << 30);
|
||||
|
||||
V128 v30 = MakeVectorE0E1(z, z);
|
||||
V128 v31 = MakeVectorE0E1(table0, table0);
|
||||
V128 v0 = MakeVectorE0E1(table1, table1);
|
||||
V128 v1 = MakeVectorE0E1(table2, table2);
|
||||
V128 v2 = MakeVectorE0E1(table3, table3);
|
||||
V128 v3 = MakeVectorE0E1(indexes, indexes);
|
||||
|
||||
SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3, v30: v30, v31: v31);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
69
src/Ryujinx.Tests/Cpu/CpuTestSystem.cs
Normal file
69
src/Ryujinx.Tests/Cpu/CpuTestSystem.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
#define System
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("System")]
|
||||
public sealed class CpuTestSystem : CpuTest
|
||||
{
|
||||
#if System
|
||||
|
||||
#region "ValueSource (Types)"
|
||||
private static IEnumerable<ulong> _GenNzcv_()
|
||||
{
|
||||
yield return 0x0000000000000000ul;
|
||||
yield return 0x7FFFFFFFFFFFFFFFul;
|
||||
yield return 0x8000000000000000ul;
|
||||
yield return 0xFFFFFFFFFFFFFFFFul;
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
ulong rnd = 0UL;
|
||||
|
||||
rnd |= (v ? 1UL : 0UL) << (int)PState.VFlag;
|
||||
rnd |= (c ? 1UL : 0UL) << (int)PState.CFlag;
|
||||
rnd |= (z ? 1UL : 0UL) << (int)PState.ZFlag;
|
||||
rnd |= (n ? 1UL : 0UL) << (int)PState.NFlag;
|
||||
|
||||
yield return rnd;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "ValueSource (Opcodes)"
|
||||
private static uint[] _MrsMsr_Nzcv_()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xD53B4200u, // MRS X0, NZCV
|
||||
0xD51B4200u // MSR NZCV, X0
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Test, Pairwise]
|
||||
public void MrsMsr_Nzcv([ValueSource("_MrsMsr_Nzcv_")] uint opcodes,
|
||||
[Values(0u, 1u, 31u)] uint rt,
|
||||
[ValueSource("_GenNzcv_")] ulong xt)
|
||||
{
|
||||
opcodes |= (rt & 31) << 0;
|
||||
|
||||
bool v = TestContext.CurrentContext.Random.NextBool();
|
||||
bool c = TestContext.CurrentContext.Random.NextBool();
|
||||
bool z = TestContext.CurrentContext.Random.NextBool();
|
||||
bool n = TestContext.CurrentContext.Random.NextBool();
|
||||
|
||||
ulong x31 = TestContext.CurrentContext.Random.NextULong();
|
||||
|
||||
SingleOpcode(opcodes, x0: xt, x1: xt, x31: x31, overflow: v, carry: c, zero: z, negative: n);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
1014
src/Ryujinx.Tests/Cpu/CpuTestT32Alu.cs
Normal file
1014
src/Ryujinx.Tests/Cpu/CpuTestT32Alu.cs
Normal file
File diff suppressed because it is too large
Load diff
167
src/Ryujinx.Tests/Cpu/CpuTestT32Flow.cs
Normal file
167
src/Ryujinx.Tests/Cpu/CpuTestT32Flow.cs
Normal file
|
@ -0,0 +1,167 @@
|
|||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("T32Flow")]
|
||||
public sealed class CpuTestT32Flow : CpuTest32
|
||||
{
|
||||
[Test]
|
||||
public void TestT32B1()
|
||||
{
|
||||
// BNE label
|
||||
ThumbOpcode(0xf040);
|
||||
ThumbOpcode(0x8240);
|
||||
for (int i = 0; i < 576; i++)
|
||||
{
|
||||
ThumbOpcode(0xe7fe);
|
||||
}
|
||||
// label: BX LR
|
||||
ThumbOpcode(0x4770);
|
||||
|
||||
GetContext().SetPstateFlag(PState.TFlag, true);
|
||||
|
||||
ExecuteOpcodes(runUnicorn: false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestT32B2()
|
||||
{
|
||||
// BNE label1
|
||||
ThumbOpcode(0xf040);
|
||||
ThumbOpcode(0x8242);
|
||||
// label2: BNE label3
|
||||
ThumbOpcode(0xf040);
|
||||
ThumbOpcode(0x8242);
|
||||
for (int i = 0; i < 576; i++)
|
||||
{
|
||||
ThumbOpcode(0xe7fe);
|
||||
}
|
||||
// label1: BNE label2
|
||||
ThumbOpcode(0xf47f);
|
||||
ThumbOpcode(0xadbc);
|
||||
// label3: BX LR
|
||||
ThumbOpcode(0x4770);
|
||||
|
||||
GetContext().SetPstateFlag(PState.TFlag, true);
|
||||
|
||||
ExecuteOpcodes(runUnicorn: false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestT32B3()
|
||||
{
|
||||
// B.W label
|
||||
ThumbOpcode(0xf000);
|
||||
ThumbOpcode(0xba40);
|
||||
for (int i = 0; i < 576; i++)
|
||||
{
|
||||
ThumbOpcode(0xe7fe);
|
||||
}
|
||||
// label: BX LR
|
||||
ThumbOpcode(0x4770);
|
||||
|
||||
GetContext().SetPstateFlag(PState.TFlag, true);
|
||||
|
||||
ExecuteOpcodes(runUnicorn: false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestT32B4()
|
||||
{
|
||||
// B.W label1
|
||||
ThumbOpcode(0xf000);
|
||||
ThumbOpcode(0xba42);
|
||||
// label2: B.W label3
|
||||
ThumbOpcode(0xf000);
|
||||
ThumbOpcode(0xba42);
|
||||
for (int i = 0; i < 576; i++)
|
||||
{
|
||||
ThumbOpcode(0xe7fe);
|
||||
}
|
||||
// label1: B.W label2
|
||||
ThumbOpcode(0xf7ff);
|
||||
ThumbOpcode(0xbdbc);
|
||||
// label3: BX LR
|
||||
ThumbOpcode(0x4770);
|
||||
|
||||
GetContext().SetPstateFlag(PState.TFlag, true);
|
||||
|
||||
ExecuteOpcodes(runUnicorn: false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestT32Bl()
|
||||
{
|
||||
// BL label
|
||||
ThumbOpcode(0xf000);
|
||||
ThumbOpcode(0xf840);
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
ThumbOpcode(0xe7fe);
|
||||
}
|
||||
ThumbOpcode(0x4670); // label: MOV R0, LR
|
||||
ThumbOpcode(0x2100); // MOVS R1, #0
|
||||
ThumbOpcode(0x468e); // MOV LR, R1
|
||||
ThumbOpcode(0x4770); // BX LR
|
||||
|
||||
GetContext().SetPstateFlag(PState.TFlag, true);
|
||||
|
||||
ExecuteOpcodes(runUnicorn: false);
|
||||
|
||||
Assert.That(GetContext().GetX(0), Is.EqualTo(0x1005));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestT32Blx1()
|
||||
{
|
||||
// BLX label
|
||||
ThumbOpcode(0xf000);
|
||||
ThumbOpcode(0xe840);
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
ThumbOpcode(0x4770);
|
||||
}
|
||||
// .arm ; label: MOV R0, LR
|
||||
Opcode(0xe1a0000e);
|
||||
// MOV LR, #0
|
||||
Opcode(0xe3a0e000);
|
||||
// BX LR
|
||||
Opcode(0xe12fff1e);
|
||||
|
||||
GetContext().SetPstateFlag(PState.TFlag, true);
|
||||
|
||||
ExecuteOpcodes(runUnicorn: false);
|
||||
|
||||
Assert.That(GetContext().GetX(0), Is.EqualTo(0x1005));
|
||||
Assert.That(GetContext().GetPstateFlag(PState.TFlag), Is.EqualTo(false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestT32Blx2()
|
||||
{
|
||||
// NOP
|
||||
ThumbOpcode(0xbf00);
|
||||
// BLX label
|
||||
ThumbOpcode(0xf000);
|
||||
ThumbOpcode(0xe840);
|
||||
for (int i = 0; i < 63; i++)
|
||||
{
|
||||
ThumbOpcode(0x4770);
|
||||
}
|
||||
// .arm ; label: MOV R0, LR
|
||||
Opcode(0xe1a0000e);
|
||||
// MOV LR, #0
|
||||
Opcode(0xe3a0e000);
|
||||
// BX LR
|
||||
Opcode(0xe12fff1e);
|
||||
|
||||
GetContext().SetPstateFlag(PState.TFlag, true);
|
||||
|
||||
ExecuteOpcodes(runUnicorn: false);
|
||||
|
||||
Assert.That(GetContext().GetX(0), Is.EqualTo(0x1007));
|
||||
Assert.That(GetContext().GetPstateFlag(PState.TFlag), Is.EqualTo(false));
|
||||
}
|
||||
}
|
||||
}
|
520
src/Ryujinx.Tests/Cpu/CpuTestT32Mem.cs
Normal file
520
src/Ryujinx.Tests/Cpu/CpuTestT32Mem.cs
Normal file
|
@ -0,0 +1,520 @@
|
|||
using NUnit.Framework;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("T32Mem")]
|
||||
public sealed class CpuTestT32Mem : CpuTest32
|
||||
{
|
||||
[Test]
|
||||
public void TestT32MemImm([ValueSource(nameof(ImmTestCases))] PrecomputedMemoryThumbTestCase test)
|
||||
{
|
||||
RunPrecomputedTestCase(test);
|
||||
}
|
||||
|
||||
public static readonly PrecomputedMemoryThumbTestCase[] ImmTestCases =
|
||||
{
|
||||
// STRB (imm8)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf80c, 0x1b2f, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000023bd, 0x000027bb, 0x00002715, 0x000028f5, 0x0000233f, 0x0000213b, 0x00002eea, 0x0000282b, 0x000021e1, 0x0000264c, 0x000029e0, 0x00002ae7, 0x000021ff, 0x000026e3, 0x00000001, 0x800001f0 },
|
||||
FinalRegs = new uint[] { 0x000023bd, 0x000027bb, 0x00002715, 0x000028f5, 0x0000233f, 0x0000213b, 0x00002eea, 0x0000282b, 0x000021e1, 0x0000264c, 0x000029e0, 0x00002ae7, 0x0000222e, 0x000026e3, 0x00000001, 0x800001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x21fe, Value: 0xbbfe) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf80a, 0x2f81, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000223c, 0x00002db9, 0x00002900, 0x0000247c, 0x00002b0a, 0x0000266b, 0x000026df, 0x00002447, 0x000024bb, 0x00002687, 0x0000266f, 0x00002a80, 0x000025ff, 0x00002881, 0x00000001, 0xa00001f0 },
|
||||
FinalRegs = new uint[] { 0x0000223c, 0x00002db9, 0x00002900, 0x0000247c, 0x00002b0a, 0x0000266b, 0x000026df, 0x00002447, 0x000024bb, 0x00002687, 0x000026f0, 0x00002a80, 0x000025ff, 0x00002881, 0x00000001, 0xa00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x26f0, Value: 0x2600) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf803, 0x6968, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000026ed, 0x00002685, 0x00002cd1, 0x00002dac, 0x00002a23, 0x00002626, 0x00002ec9, 0x0000245c, 0x000024ef, 0x00002319, 0x000026ce, 0x0000214d, 0x00002401, 0x000028b4, 0x00000001, 0x300001f0 },
|
||||
FinalRegs = new uint[] { 0x000026ed, 0x00002685, 0x00002cd1, 0x00002d44, 0x00002a23, 0x00002626, 0x00002ec9, 0x0000245c, 0x000024ef, 0x00002319, 0x000026ce, 0x0000214d, 0x00002401, 0x000028b4, 0x00000001, 0x300001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2dac, Value: 0x2dc9) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf804, 0x89ad, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000265d, 0x00002b9c, 0x00002360, 0x000029ec, 0x00002413, 0x00002d8e, 0x00002aad, 0x00002d29, 0x00002bca, 0x00002a44, 0x00002980, 0x00002710, 0x000022fa, 0x0000222e, 0x00000001, 0xc00001f0 },
|
||||
FinalRegs = new uint[] { 0x0000265d, 0x00002b9c, 0x00002360, 0x000029ec, 0x00002366, 0x00002d8e, 0x00002aad, 0x00002d29, 0x00002bca, 0x00002a44, 0x00002980, 0x00002710, 0x000022fa, 0x0000222e, 0x00000001, 0xc00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2412, Value: 0xca12) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf80d, 0xa9fe, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000298d, 0x00002e6c, 0x00002986, 0x00002ebb, 0x0000213e, 0x00002e39, 0x0000246f, 0x00002b6c, 0x00002ee2, 0x0000259e, 0x0000250a, 0x000029f6, 0x000021e7, 0x00002d9d, 0x00000001, 0x900001f0 },
|
||||
FinalRegs = new uint[] { 0x0000298d, 0x00002e6c, 0x00002986, 0x00002ebb, 0x0000213e, 0x00002e39, 0x0000246f, 0x00002b6c, 0x00002ee2, 0x0000259e, 0x0000250a, 0x000029f6, 0x000021e7, 0x00002c9f, 0x00000001, 0x900001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2d9c, Value: 0x0a9c) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf80d, 0x3c46, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002c6f, 0x000028cc, 0x000025f0, 0x000022cc, 0x00002de3, 0x0000243c, 0x000025fb, 0x00002e88, 0x00002985, 0x000023ee, 0x00002120, 0x00002d50, 0x0000270a, 0x00002bbd, 0x00000001, 0xa00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002c6f, 0x000028cc, 0x000025f0, 0x000022cc, 0x00002de3, 0x0000243c, 0x000025fb, 0x00002e88, 0x00002985, 0x000023ee, 0x00002120, 0x00002d50, 0x0000270a, 0x00002bbd, 0x00000001, 0xa00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2b76, Value: 0xcc76) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf801, 0x6c56, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002d6e, 0x00002530, 0x00002e6d, 0x00002942, 0x00002985, 0x00002d64, 0x00002a73, 0x00002ac6, 0x00002955, 0x00002881, 0x0000221d, 0x00002cb0, 0x0000225f, 0x00002534, 0x00000001, 0x100001f0 },
|
||||
FinalRegs = new uint[] { 0x00002d6e, 0x00002530, 0x00002e6d, 0x00002942, 0x00002985, 0x00002d64, 0x00002a73, 0x00002ac6, 0x00002955, 0x00002881, 0x0000221d, 0x00002cb0, 0x0000225f, 0x00002534, 0x00000001, 0x100001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x24da, Value: 0x2473) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf809, 0xcc76, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002d50, 0x000025f2, 0x0000250a, 0x0000214c, 0x000023d1, 0x00002115, 0x00002c27, 0x00002540, 0x0000222b, 0x00002d03, 0x00002679, 0x00002b52, 0x00002eee, 0x00002b2a, 0x00000001, 0xd00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002d50, 0x000025f2, 0x0000250a, 0x0000214c, 0x000023d1, 0x00002115, 0x00002c27, 0x00002540, 0x0000222b, 0x00002d03, 0x00002679, 0x00002b52, 0x00002eee, 0x00002b2a, 0x00000001, 0xd00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2c8c, Value: 0xee8c) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf808, 0x1c8d, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002844, 0x00002b78, 0x000028b0, 0x000026ff, 0x0000280b, 0x00002e0b, 0x00002de4, 0x00002b53, 0x00002ecd, 0x000021b5, 0x000026bc, 0x00002e9d, 0x00002d33, 0x000027f0, 0x00000001, 0x800001f0 },
|
||||
FinalRegs = new uint[] { 0x00002844, 0x00002b78, 0x000028b0, 0x000026ff, 0x0000280b, 0x00002e0b, 0x00002de4, 0x00002b53, 0x00002ecd, 0x000021b5, 0x000026bc, 0x00002e9d, 0x00002d33, 0x000027f0, 0x00000001, 0x800001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2e40, Value: 0x2e78) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf80b, 0xbc26, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002244, 0x000025ad, 0x00002434, 0x00002b06, 0x00002ebd, 0x0000292b, 0x00002431, 0x00002e12, 0x0000289b, 0x0000265a, 0x00002747, 0x00002bac, 0x00002dae, 0x00002582, 0x00000001, 0xf00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002244, 0x000025ad, 0x00002434, 0x00002b06, 0x00002ebd, 0x0000292b, 0x00002431, 0x00002e12, 0x0000289b, 0x0000265a, 0x00002747, 0x00002bac, 0x00002dae, 0x00002582, 0x00000001, 0xf00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2b86, Value: 0x2bac) },
|
||||
},
|
||||
// STRB (imm12)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf887, 0x67c2, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x700001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x700001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x27c2, Value: 0x2700) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf883, 0x9fda, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xc00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xc00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2fda, Value: 0x2f00) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf889, 0xd200, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x400001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x400001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf88c, 0x1c5b, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x500001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x500001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2c5a, Value: 0x005a) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf887, 0x9fe2, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xe00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xe00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2fe2, Value: 0x2f00) },
|
||||
},
|
||||
// STRH (imm8)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf826, 0x0b0a, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000025a2, 0x000024d5, 0x00002ca1, 0x0000238a, 0x0000279c, 0x0000244c, 0x00002620, 0x00002c0e, 0x0000233e, 0x0000285f, 0x000021ab, 0x00002bd0, 0x0000281f, 0x00002be7, 0x00000001, 0x600001f0 },
|
||||
FinalRegs = new uint[] { 0x000025a2, 0x000024d5, 0x00002ca1, 0x0000238a, 0x0000279c, 0x0000244c, 0x0000262a, 0x00002c0e, 0x0000233e, 0x0000285f, 0x000021ab, 0x00002bd0, 0x0000281f, 0x00002be7, 0x00000001, 0x600001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2620, Value: 0x25a2) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf827, 0xcf61, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002555, 0x0000238f, 0x00002829, 0x000028c8, 0x00002399, 0x00002aab, 0x00002d6f, 0x000029eb, 0x000029e0, 0x00002d33, 0x0000292a, 0x00002b33, 0x00002e29, 0x00002ca4, 0x00000001, 0x100001f0 },
|
||||
FinalRegs = new uint[] { 0x00002555, 0x0000238f, 0x00002829, 0x000028c8, 0x00002399, 0x00002aab, 0x00002d6f, 0x00002a4c, 0x000029e0, 0x00002d33, 0x0000292a, 0x00002b33, 0x00002e29, 0x00002ca4, 0x00000001, 0x100001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2a4c, Value: 0x2e29) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf821, 0x9b00, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000027ba, 0x00002514, 0x00002b07, 0x00002daf, 0x00002790, 0x0000274b, 0x00002379, 0x00002a98, 0x000024c8, 0x00002398, 0x000021ba, 0x00002959, 0x00002821, 0x00002d09, 0x00000001, 0x500001f0 },
|
||||
FinalRegs = new uint[] { 0x000027ba, 0x00002514, 0x00002b07, 0x00002daf, 0x00002790, 0x0000274b, 0x00002379, 0x00002a98, 0x000024c8, 0x00002398, 0x000021ba, 0x00002959, 0x00002821, 0x00002d09, 0x00000001, 0x500001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2514, Value: 0x2398) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf82c, 0xa927, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000226a, 0x00002792, 0x00002870, 0x00002918, 0x00002757, 0x00002679, 0x00002546, 0x000027f5, 0x00002edc, 0x00002cd3, 0x0000274a, 0x00002562, 0x000029a1, 0x00002976, 0x00000001, 0x100001f0 },
|
||||
FinalRegs = new uint[] { 0x0000226a, 0x00002792, 0x00002870, 0x00002918, 0x00002757, 0x00002679, 0x00002546, 0x000027f5, 0x00002edc, 0x00002cd3, 0x0000274a, 0x00002562, 0x0000297a, 0x00002976, 0x00000001, 0x100001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x29a0, Value: 0x4aa0), (Address: 0x29a2, Value: 0x2927) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf824, 0xcfe4, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000238b, 0x00002d22, 0x00002476, 0x000028ae, 0x00002442, 0x0000212b, 0x000026de, 0x00002a1a, 0x00002a02, 0x00002e47, 0x00002b2d, 0x00002427, 0x00002d1c, 0x000026d4, 0x00000001, 0xd00001f0 },
|
||||
FinalRegs = new uint[] { 0x0000238b, 0x00002d22, 0x00002476, 0x000028ae, 0x00002526, 0x0000212b, 0x000026de, 0x00002a1a, 0x00002a02, 0x00002e47, 0x00002b2d, 0x00002427, 0x00002d1c, 0x000026d4, 0x00000001, 0xd00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2526, Value: 0x2d1c) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf820, 0x1c3d, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002227, 0x00002b29, 0x0000232a, 0x0000214e, 0x000029ef, 0x00002522, 0x000029d3, 0x0000286c, 0x000029b2, 0x00002147, 0x00002c65, 0x00002891, 0x000029c2, 0x000028a5, 0x00000001, 0x800001f0 },
|
||||
FinalRegs = new uint[] { 0x00002227, 0x00002b29, 0x0000232a, 0x0000214e, 0x000029ef, 0x00002522, 0x000029d3, 0x0000286c, 0x000029b2, 0x00002147, 0x00002c65, 0x00002891, 0x000029c2, 0x000028a5, 0x00000001, 0x800001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x21ea, Value: 0x2b29) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf826, 0x1cdf, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002232, 0x000029a1, 0x00002938, 0x00002ae7, 0x000029a4, 0x00002366, 0x0000273a, 0x000023f6, 0x00002601, 0x00002919, 0x000028e3, 0x00002907, 0x000023c1, 0x00002138, 0x00000001, 0x100001f0 },
|
||||
FinalRegs = new uint[] { 0x00002232, 0x000029a1, 0x00002938, 0x00002ae7, 0x000029a4, 0x00002366, 0x0000273a, 0x000023f6, 0x00002601, 0x00002919, 0x000028e3, 0x00002907, 0x000023c1, 0x00002138, 0x00000001, 0x100001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x265a, Value: 0xa15a), (Address: 0x265c, Value: 0x2629) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf82b, 0x3c66, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002974, 0x00002372, 0x0000276c, 0x000021df, 0x00002272, 0x00002928, 0x00002c50, 0x0000290e, 0x00002319, 0x000021d1, 0x00002a82, 0x000027ff, 0x00002730, 0x000027b2, 0x00000001, 0x700001f0 },
|
||||
FinalRegs = new uint[] { 0x00002974, 0x00002372, 0x0000276c, 0x000021df, 0x00002272, 0x00002928, 0x00002c50, 0x0000290e, 0x00002319, 0x000021d1, 0x00002a82, 0x000027ff, 0x00002730, 0x000027b2, 0x00000001, 0x700001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2798, Value: 0xdf98), (Address: 0x279a, Value: 0x2721) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf822, 0x3c06, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000021b8, 0x00002357, 0x00002b00, 0x00002207, 0x00002648, 0x0000219c, 0x000021d2, 0x000023b0, 0x00002368, 0x00002a41, 0x000026ac, 0x00002a86, 0x00002879, 0x00002c1d, 0x00000001, 0x700001f0 },
|
||||
FinalRegs = new uint[] { 0x000021b8, 0x00002357, 0x00002b00, 0x00002207, 0x00002648, 0x0000219c, 0x000021d2, 0x000023b0, 0x00002368, 0x00002a41, 0x000026ac, 0x00002a86, 0x00002879, 0x00002c1d, 0x00000001, 0x700001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2afa, Value: 0x2207) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf824, 0xac84, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002796, 0x000027c8, 0x0000241b, 0x0000214d, 0x0000220b, 0x00002587, 0x00002130, 0x00002910, 0x00002ac2, 0x00002e74, 0x000028f8, 0x000024bf, 0x0000263a, 0x00002625, 0x00000001, 0x600001f0 },
|
||||
FinalRegs = new uint[] { 0x00002796, 0x000027c8, 0x0000241b, 0x0000214d, 0x0000220b, 0x00002587, 0x00002130, 0x00002910, 0x00002ac2, 0x00002e74, 0x000028f8, 0x000024bf, 0x0000263a, 0x00002625, 0x00000001, 0x600001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2186, Value: 0xf886), (Address: 0x2188, Value: 0x2128) },
|
||||
},
|
||||
// STRH (imm12)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8a5, 0x59d4, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x000001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x000001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x29d4, Value: 0x2000) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8ac, 0xc533, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xe00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xe00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2532, Value: 0x0032), (Address: 0x2534, Value: 0x2520) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8a3, 0xb559, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x000001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x000001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2558, Value: 0x0058), (Address: 0x255a, Value: 0x2520) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8a5, 0xdb3a, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xb00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xb00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2b3a, Value: 0x2000) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8a9, 0x02cc, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xc00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xc00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x22cc, Value: 0x2000) },
|
||||
},
|
||||
// STR (imm8)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf846, 0x1fb4, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002b17, 0x0000272f, 0x00002483, 0x0000284c, 0x0000287f, 0x0000238f, 0x0000222d, 0x00002259, 0x0000249d, 0x00002e3f, 0x00002323, 0x00002729, 0x000025c1, 0x00002866, 0x00000001, 0x900001f0 },
|
||||
FinalRegs = new uint[] { 0x00002b17, 0x0000272f, 0x00002483, 0x0000284c, 0x0000287f, 0x0000238f, 0x000022e1, 0x00002259, 0x0000249d, 0x00002e3f, 0x00002323, 0x00002729, 0x000025c1, 0x00002866, 0x00000001, 0x900001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x22e0, Value: 0x2fe0), (Address: 0x22e2, Value: 0x0027), (Address: 0x22e4, Value: 0x2200) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf844, 0x3f11, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000028e1, 0x00002d48, 0x000027d6, 0x000023ac, 0x000027bb, 0x000026cf, 0x000023c1, 0x00002633, 0x0000214b, 0x00002434, 0x0000239a, 0x000025c6, 0x00002148, 0x00002d1f, 0x00000001, 0x300001f0 },
|
||||
FinalRegs = new uint[] { 0x000028e1, 0x00002d48, 0x000027d6, 0x000023ac, 0x000027cc, 0x000026cf, 0x000023c1, 0x00002633, 0x0000214b, 0x00002434, 0x0000239a, 0x000025c6, 0x00002148, 0x00002d1f, 0x00000001, 0x300001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x27cc, Value: 0x23ac), (Address: 0x27ce, Value: 0x0000) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf847, 0x09c2, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000248b, 0x00002396, 0x000023c5, 0x00002be0, 0x0000237d, 0x00002191, 0x00002da0, 0x0000211c, 0x00002d24, 0x000021e6, 0x000024ff, 0x00002268, 0x00002968, 0x0000244d, 0x00000001, 0x800001f0 },
|
||||
FinalRegs = new uint[] { 0x0000248b, 0x00002396, 0x000023c5, 0x00002be0, 0x0000237d, 0x00002191, 0x00002da0, 0x0000205a, 0x00002d24, 0x000021e6, 0x000024ff, 0x00002268, 0x00002968, 0x0000244d, 0x00000001, 0x800001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x211c, Value: 0x248b), (Address: 0x211e, Value: 0x0000) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf84d, 0x7f23, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000025b0, 0x0000260e, 0x00002343, 0x00002e36, 0x000024c5, 0x000029bc, 0x0000278e, 0x00002b63, 0x00002ce7, 0x000029af, 0x000023bf, 0x00002475, 0x00002197, 0x00002c33, 0x00000001, 0x200001f0 },
|
||||
FinalRegs = new uint[] { 0x000025b0, 0x0000260e, 0x00002343, 0x00002e36, 0x000024c5, 0x000029bc, 0x0000278e, 0x00002b63, 0x00002ce7, 0x000029af, 0x000023bf, 0x00002475, 0x00002197, 0x00002c56, 0x00000001, 0x200001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2c56, Value: 0x2b63), (Address: 0x2c58, Value: 0x0000) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf843, 0x9d24, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002ce4, 0x00002e0e, 0x000026d5, 0x000025fb, 0x00002b78, 0x0000215a, 0x00002af7, 0x0000259c, 0x00002645, 0x000027dc, 0x00002163, 0x000028f5, 0x000029df, 0x0000230b, 0x00000001, 0x500001f0 },
|
||||
FinalRegs = new uint[] { 0x00002ce4, 0x00002e0e, 0x000026d5, 0x000025d7, 0x00002b78, 0x0000215a, 0x00002af7, 0x0000259c, 0x00002645, 0x000027dc, 0x00002163, 0x000028f5, 0x000029df, 0x0000230b, 0x00000001, 0x500001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x25d6, Value: 0xdcd6), (Address: 0x25d8, Value: 0x0027), (Address: 0x25da, Value: 0x2500) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf849, 0xdc1a, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002d98, 0x0000254a, 0x00002540, 0x00002324, 0x0000264e, 0x00002523, 0x0000271f, 0x00002875, 0x000023b3, 0x00002680, 0x00002223, 0x000022bf, 0x000025f4, 0x00002d81, 0x00000001, 0x700001f0 },
|
||||
FinalRegs = new uint[] { 0x00002d98, 0x0000254a, 0x00002540, 0x00002324, 0x0000264e, 0x00002523, 0x0000271f, 0x00002875, 0x000023b3, 0x00002680, 0x00002223, 0x000022bf, 0x000025f4, 0x00002d81, 0x00000001, 0x700001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2666, Value: 0x2d81), (Address: 0x2668, Value: 0x0000) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf849, 0x0cd1, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000255a, 0x00002655, 0x00002276, 0x000022e4, 0x00002eef, 0x00002e99, 0x00002b55, 0x00002a40, 0x00002661, 0x00002dbd, 0x00002687, 0x000024e1, 0x000023ea, 0x00002b88, 0x00000001, 0xc00001f0 },
|
||||
FinalRegs = new uint[] { 0x0000255a, 0x00002655, 0x00002276, 0x000022e4, 0x00002eef, 0x00002e99, 0x00002b55, 0x00002a40, 0x00002661, 0x00002dbd, 0x00002687, 0x000024e1, 0x000023ea, 0x00002b88, 0x00000001, 0xc00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2cec, Value: 0x255a), (Address: 0x2cee, Value: 0x0000) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf847, 0x7c96, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000027f6, 0x0000222a, 0x000024e1, 0x00002a2d, 0x00002ee8, 0x000023f2, 0x000029de, 0x00002a53, 0x000029da, 0x00002d2c, 0x00002d6f, 0x000026b8, 0x00002777, 0x00002e3a, 0x00000001, 0xf00001f0 },
|
||||
FinalRegs = new uint[] { 0x000027f6, 0x0000222a, 0x000024e1, 0x00002a2d, 0x00002ee8, 0x000023f2, 0x000029de, 0x00002a53, 0x000029da, 0x00002d2c, 0x00002d6f, 0x000026b8, 0x00002777, 0x00002e3a, 0x00000001, 0xf00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x29bc, Value: 0x53bc), (Address: 0x29be, Value: 0x002a), (Address: 0x29c0, Value: 0x2900) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf84d, 0x8cbd, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002a58, 0x00002a59, 0x00002dfd, 0x00002ba8, 0x00002929, 0x00002146, 0x00002706, 0x000025f3, 0x000023d7, 0x0000221f, 0x000027ae, 0x00002a6e, 0x00002824, 0x00002357, 0x00000001, 0x600001f0 },
|
||||
FinalRegs = new uint[] { 0x00002a58, 0x00002a59, 0x00002dfd, 0x00002ba8, 0x00002929, 0x00002146, 0x00002706, 0x000025f3, 0x000023d7, 0x0000221f, 0x000027ae, 0x00002a6e, 0x00002824, 0x00002357, 0x00000001, 0x600001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x229a, Value: 0x23d7), (Address: 0x229c, Value: 0x0000) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf846, 0xacaf, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000284f, 0x00002def, 0x0000292f, 0x000021e8, 0x0000274e, 0x00002518, 0x00002538, 0x00002375, 0x00002d28, 0x0000229a, 0x0000255f, 0x00002eca, 0x00002e15, 0x000021aa, 0x00000001, 0x100001f0 },
|
||||
FinalRegs = new uint[] { 0x0000284f, 0x00002def, 0x0000292f, 0x000021e8, 0x0000274e, 0x00002518, 0x00002538, 0x00002375, 0x00002d28, 0x0000229a, 0x0000255f, 0x00002eca, 0x00002e15, 0x000021aa, 0x00000001, 0x100001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2488, Value: 0x5f88), (Address: 0x248a, Value: 0x0025), (Address: 0x248c, Value: 0x2400) },
|
||||
},
|
||||
// STR (imm12)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8cc, 0x1a6e, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x500001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x500001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2a6e, Value: 0x2000), (Address: 0x2a70, Value: 0x0000) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8c9, 0xcfc1, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xe00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xe00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x2fc0, Value: 0x00c0), (Address: 0x2fc2, Value: 0x0020), (Address: 0x2fc4, Value: 0x2f00) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8c3, 0xb5dd, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x600001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x600001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x25dc, Value: 0x00dc), (Address: 0x25de, Value: 0x0020), (Address: 0x25e0, Value: 0x2500) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8c0, 0x69e9, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xe00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xe00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x29e8, Value: 0x00e8), (Address: 0x29ea, Value: 0x0020), (Address: 0x29ec, Value: 0x2900) },
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8cd, 0x028f, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x600001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x600001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] { (Address: 0x228e, Value: 0x008e), (Address: 0x2290, Value: 0x0020), (Address: 0x2292, Value: 0x2200) },
|
||||
},
|
||||
// LDRB (imm8)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf816, 0x1c48, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002cb8, 0x00002345, 0x00002ebc, 0x00002db8, 0x000021d4, 0x000026e4, 0x00002458, 0x000029e3, 0x000028d2, 0x000027f4, 0x000023d6, 0x00002def, 0x0000285c, 0x00002d06, 0x00000001, 0x600001f0 },
|
||||
FinalRegs = new uint[] { 0x00002cb8, 0x00000010, 0x00002ebc, 0x00002db8, 0x000021d4, 0x000026e4, 0x00002458, 0x000029e3, 0x000028d2, 0x000027f4, 0x000023d6, 0x00002def, 0x0000285c, 0x00002d06, 0x00000001, 0x600001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf815, 0x2d6e, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000021e4, 0x00002425, 0x00002e42, 0x00002a58, 0x00002708, 0x00002965, 0x00002a1d, 0x00002ed5, 0x00002cc4, 0x000026e1, 0x00002b4b, 0x00002ade, 0x00002824, 0x00002975, 0x00000001, 0x100001f0 },
|
||||
FinalRegs = new uint[] { 0x000021e4, 0x00002425, 0x00000028, 0x00002a58, 0x00002708, 0x000028f7, 0x00002a1d, 0x00002ed5, 0x00002cc4, 0x000026e1, 0x00002b4b, 0x00002ade, 0x00002824, 0x00002975, 0x00000001, 0x100001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf818, 0x0d33, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002492, 0x0000214d, 0x00002827, 0x000021af, 0x0000215e, 0x000028d6, 0x000024ec, 0x00002984, 0x0000297b, 0x000024b5, 0x000024ca, 0x0000298f, 0x00002339, 0x00002b7e, 0x00000001, 0xd00001f0 },
|
||||
FinalRegs = new uint[] { 0x00000048, 0x0000214d, 0x00002827, 0x000021af, 0x0000215e, 0x000028d6, 0x000024ec, 0x00002984, 0x00002948, 0x000024b5, 0x000024ca, 0x0000298f, 0x00002339, 0x00002b7e, 0x00000001, 0xd00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf810, 0xbff3, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002ea6, 0x000024fa, 0x00002346, 0x00002748, 0x0000283f, 0x00002770, 0x000023e3, 0x000021aa, 0x0000214a, 0x00002d58, 0x00002159, 0x000022e7, 0x00002242, 0x00002728, 0x00000001, 0x600001f0 },
|
||||
FinalRegs = new uint[] { 0x00002f99, 0x000024fa, 0x00002346, 0x00002748, 0x0000283f, 0x00002770, 0x000023e3, 0x000021aa, 0x0000214a, 0x00002d58, 0x00002159, 0x0000002f, 0x00002242, 0x00002728, 0x00000001, 0x600001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
// LDRB (imm12)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf892, 0xcc8f, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x100001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x0000002c, 0x00002000, 0x00000001, 0x100001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf89a, 0x7fdc, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x200001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x000000dc, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x200001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf890, 0x5f9f, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x800001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x0000002f, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x800001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf894, 0xdda1, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x900001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x0000002d, 0x00000001, 0x900001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf890, 0xc281, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x100001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000022, 0x00002000, 0x00000001, 0x100001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
// LDRH (imm8)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf834, 0x89d8, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002a9e, 0x00002d84, 0x00002e9b, 0x00002e7f, 0x000024a2, 0x00002b7b, 0x00002e3b, 0x0000299a, 0x00002dff, 0x00002a9e, 0x000027b2, 0x00002a90, 0x00002883, 0x0000288d, 0x00000001, 0x500001f0 },
|
||||
FinalRegs = new uint[] { 0x00002a9e, 0x00002d84, 0x00002e9b, 0x00002e7f, 0x000023ca, 0x00002b7b, 0x00002e3b, 0x0000299a, 0x000024a2, 0x00002a9e, 0x000027b2, 0x00002a90, 0x00002883, 0x0000288d, 0x00000001, 0x500001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf833, 0x6be4, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000028bd, 0x00002b0e, 0x00002bc1, 0x00002a83, 0x00002293, 0x00002c7c, 0x00002bfe, 0x00002eb7, 0x0000299b, 0x000026e6, 0x0000219c, 0x00002d5e, 0x00002cd4, 0x000026cf, 0x00000001, 0xd00001f0 },
|
||||
FinalRegs = new uint[] { 0x000028bd, 0x00002b0e, 0x00002bc1, 0x00002b67, 0x00002293, 0x00002c7c, 0x0000842a, 0x00002eb7, 0x0000299b, 0x000026e6, 0x0000219c, 0x00002d5e, 0x00002cd4, 0x000026cf, 0x00000001, 0xd00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf83d, 0x1bca, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000250e, 0x00002776, 0x000029e5, 0x0000276e, 0x00002c6b, 0x00002712, 0x00002a85, 0x00002d56, 0x000024c0, 0x00002d86, 0x0000254a, 0x00002549, 0x00002795, 0x00002e97, 0x00000001, 0x200001f0 },
|
||||
FinalRegs = new uint[] { 0x0000250e, 0x0000982e, 0x000029e5, 0x0000276e, 0x00002c6b, 0x00002712, 0x00002a85, 0x00002d56, 0x000024c0, 0x00002d86, 0x0000254a, 0x00002549, 0x00002795, 0x00002f61, 0x00000001, 0x200001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
// LDRH (imm12)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8b7, 0x92fc, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xa00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x000022fc, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xa00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8ba, 0xadd9, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xa00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x0000da2d, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xa00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8bb, 0x0bb0, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xd00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002bb0, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0xd00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8b8, 0xc3f8, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x600001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x000023f8, 0x00002000, 0x00000001, 0x600001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
// LDR (imm8)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf85b, 0x3fd1, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002a19, 0x00002e5b, 0x0000231b, 0x000021fa, 0x00002e95, 0x00002bd5, 0x00002e9c, 0x00002dfa, 0x000021d8, 0x00002ce1, 0x00002318, 0x00002735, 0x0000247d, 0x00002436, 0x00000001, 0xf00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002a19, 0x00002e5b, 0x0000231b, 0x28082806, 0x00002e95, 0x00002bd5, 0x00002e9c, 0x00002dfa, 0x000021d8, 0x00002ce1, 0x00002318, 0x00002806, 0x0000247d, 0x00002436, 0x00000001, 0xf00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf854, 0xab9e, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x0000214f, 0x00002578, 0x00002a98, 0x000021b0, 0x00002ebb, 0x0000284a, 0x00002319, 0x00002581, 0x00002179, 0x00002594, 0x00002373, 0x000028f4, 0x00002ec5, 0x00002e0a, 0x00000001, 0xb00001f0 },
|
||||
FinalRegs = new uint[] { 0x0000214f, 0x00002578, 0x00002a98, 0x000021b0, 0x00002f59, 0x0000284a, 0x00002319, 0x00002581, 0x00002179, 0x00002594, 0xbe2ebc2e, 0x000028f4, 0x00002ec5, 0x00002e0a, 0x00000001, 0xb00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf852, 0x6d2d, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002e27, 0x00002676, 0x00002bde, 0x000022d9, 0x00002362, 0x00002d4b, 0x00002dab, 0x000022b6, 0x0000229c, 0x00002507, 0x00002848, 0x0000225f, 0x00002ac2, 0x000023c3, 0x00000001, 0xf00001f0 },
|
||||
FinalRegs = new uint[] { 0x00002e27, 0x00002676, 0x00002bb1, 0x000022d9, 0x00002362, 0x00002d4b, 0xb42bb22b, 0x000022b6, 0x0000229c, 0x00002507, 0x00002848, 0x0000225f, 0x00002ac2, 0x000023c3, 0x00000001, 0xf00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf850, 0x8da5, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002559, 0x0000285e, 0x000021de, 0x00002223, 0x000023ff, 0x00002e05, 0x00002bf3, 0x000024a5, 0x00002124, 0x00002768, 0x00002a14, 0x0000219e, 0x00002739, 0x00002e3c, 0x00000001, 0xd00001f0 },
|
||||
FinalRegs = new uint[] { 0x000024b4, 0x0000285e, 0x000021de, 0x00002223, 0x000023ff, 0x00002e05, 0x00002bf3, 0x000024a5, 0x24b624b4, 0x00002768, 0x00002a14, 0x0000219e, 0x00002739, 0x00002e3c, 0x00000001, 0xd00001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf857, 0x19f6, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x000027f5, 0x0000285e, 0x000025f6, 0x00002e22, 0x00002224, 0x00002870, 0x00002ecc, 0x000024cf, 0x00002711, 0x0000241b, 0x00002ddf, 0x00002545, 0x000028ca, 0x000023c5, 0x00000001, 0x400001f0 },
|
||||
FinalRegs = new uint[] { 0x000027f5, 0xd224d024, 0x000025f6, 0x00002e22, 0x00002224, 0x00002870, 0x00002ecc, 0x000023d9, 0x00002711, 0x0000241b, 0x00002ddf, 0x00002545, 0x000028ca, 0x000023c5, 0x00000001, 0x400001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
// LDR (imm12)
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8d1, 0xc65e, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x000001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x2660265e, 0x00002000, 0x00000001, 0x000001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8db, 0xd09b, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x800001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x9e209c20, 0x00000001, 0x800001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8d2, 0x6fde, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x900001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x2fe02fde, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x900001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
new PrecomputedMemoryThumbTestCase()
|
||||
{
|
||||
Instructions = new ushort[] { 0xf8dc, 0x3de5, 0x4770, 0xe7fe },
|
||||
StartRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x500001f0 },
|
||||
FinalRegs = new uint[] { 0x00002000, 0x00002000, 0x00002000, 0xe82de62d, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00000001, 0x500001f0 },
|
||||
MemoryDelta = new (ulong Address, ushort Value)[] {},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
878
src/Ryujinx.Tests/Cpu/CpuTestThumb.cs
Normal file
878
src/Ryujinx.Tests/Cpu/CpuTestThumb.cs
Normal file
File diff suppressed because one or more lines are too long
91
src/Ryujinx.Tests/Cpu/EnvironmentTests.cs
Normal file
91
src/Ryujinx.Tests/Cpu/EnvironmentTests.cs
Normal file
|
@ -0,0 +1,91 @@
|
|||
using ARMeilleure.Translation;
|
||||
using NUnit.Framework;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
using Ryujinx.Tests.Memory;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
internal class EnvironmentTests
|
||||
{
|
||||
private static Translator _translator;
|
||||
|
||||
private void EnsureTranslator()
|
||||
{
|
||||
// Create a translator, as one is needed to register the signal handler or emit methods.
|
||||
_translator ??= new Translator(new JitMemoryAllocator(), new MockMemoryManager(), true);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
||||
private float GetDenormal()
|
||||
{
|
||||
return BitConverter.Int32BitsToSingle(1);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
|
||||
private float GetZero()
|
||||
{
|
||||
return BitConverter.Int32BitsToSingle(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This test ensures that managed methods do not reset floating point control flags.
|
||||
/// This is used to avoid changing control flags when running methods that don't require it, such as SVC calls, software memory...
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void FpFlagsPInvoke()
|
||||
{
|
||||
EnsureTranslator();
|
||||
|
||||
// Subnormal results are not flushed to zero by default.
|
||||
// This operation should not be allowed to do constant propagation, hence the methods that explicitly disallow inlining.
|
||||
Assert.AreNotEqual(GetDenormal() + GetZero(), 0f);
|
||||
|
||||
bool methodCalled = false;
|
||||
bool isFz = false;
|
||||
|
||||
var managedMethod = () =>
|
||||
{
|
||||
// Floating point math should not modify fp flags.
|
||||
float test = 2f * 3.5f;
|
||||
|
||||
if (test < 4f)
|
||||
{
|
||||
throw new System.Exception("Sanity check.");
|
||||
}
|
||||
|
||||
isFz = GetDenormal() + GetZero() == 0f;
|
||||
|
||||
try
|
||||
{
|
||||
if (test >= 4f)
|
||||
{
|
||||
throw new System.Exception("Always throws.");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Exception handling should not modify fp flags.
|
||||
|
||||
methodCalled = true;
|
||||
}
|
||||
};
|
||||
|
||||
var method = TranslatorTestMethods.GenerateFpFlagsPInvokeTest();
|
||||
|
||||
// This method sets flush-to-zero and then calls the managed method.
|
||||
// Before and after setting the flags, it ensures subnormal addition works as expected.
|
||||
// It returns a positive result if any tests fail, and 0 on success (or if the platform cannot change FP flags)
|
||||
int result = method(Marshal.GetFunctionPointerForDelegate(managedMethod));
|
||||
|
||||
// Subnormal results are not flushed to zero by default, which we should have returned to exiting the method.
|
||||
Assert.AreNotEqual(GetDenormal() + GetZero(), 0f);
|
||||
|
||||
Assert.True(result == 0);
|
||||
Assert.True(methodCalled);
|
||||
Assert.True(isFz);
|
||||
}
|
||||
}
|
||||
}
|
10
src/Ryujinx.Tests/Cpu/PrecomputedMemoryThumbTestCase.cs
Normal file
10
src/Ryujinx.Tests/Cpu/PrecomputedMemoryThumbTestCase.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
public struct PrecomputedMemoryThumbTestCase
|
||||
{
|
||||
public ushort[] Instructions;
|
||||
public uint[] StartRegs;
|
||||
public uint[] FinalRegs;
|
||||
public (ulong Address, ushort Value)[] MemoryDelta;
|
||||
};
|
||||
}
|
9
src/Ryujinx.Tests/Cpu/PrecomputedThumbTestCase.cs
Normal file
9
src/Ryujinx.Tests/Cpu/PrecomputedThumbTestCase.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
public class PrecomputedThumbTestCase
|
||||
{
|
||||
public ushort[] Instructions;
|
||||
public uint[] StartRegs;
|
||||
public uint[] FinalRegs;
|
||||
}
|
||||
}
|
71
src/Ryujinx.Tests/HLE/SoftwareKeyboardTests.cs
Normal file
71
src/Ryujinx.Tests/HLE/SoftwareKeyboardTests.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using NUnit.Framework;
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Tests.HLE
|
||||
{
|
||||
public class SoftwareKeyboardTests
|
||||
{
|
||||
[Test]
|
||||
public void StripUnicodeControlCodes_NullInput()
|
||||
{
|
||||
Assert.IsNull(SoftwareKeyboardApplet.StripUnicodeControlCodes(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StripUnicodeControlCodes_EmptyInput()
|
||||
{
|
||||
Assert.AreEqual(string.Empty, SoftwareKeyboardApplet.StripUnicodeControlCodes(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StripUnicodeControlCodes_Passthrough()
|
||||
{
|
||||
string[] prompts = new string[]
|
||||
{
|
||||
"Please name him.",
|
||||
"Name her, too.",
|
||||
"Name your friend.",
|
||||
"Name another friend.",
|
||||
"Name your pet.",
|
||||
"Favorite homemade food?",
|
||||
"What’s your favorite thing?",
|
||||
"Are you sure?",
|
||||
};
|
||||
|
||||
foreach (string prompt in prompts)
|
||||
{
|
||||
Assert.AreEqual(prompt, SoftwareKeyboardApplet.StripUnicodeControlCodes(prompt));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StripUnicodeControlCodes_StripsNewlines()
|
||||
{
|
||||
Assert.AreEqual("I am very tall", SoftwareKeyboardApplet.StripUnicodeControlCodes("I \r\nam \r\nvery \r\ntall"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StripUnicodeControlCodes_StripsDeviceControls()
|
||||
{
|
||||
// 0x13 is control code DC3 used by some games
|
||||
string specialInput = Encoding.UTF8.GetString(new byte[] { 0x13, 0x53, 0x68, 0x69, 0x6E, 0x65, 0x13 });
|
||||
Assert.AreEqual("Shine", SoftwareKeyboardApplet.StripUnicodeControlCodes(specialInput));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StripUnicodeControlCodes_StripsToEmptyString()
|
||||
{
|
||||
string specialInput = Encoding.UTF8.GetString(new byte[] { 17, 18, 19, 20 }); // DC1 - DC4 special codes
|
||||
Assert.AreEqual(string.Empty, SoftwareKeyboardApplet.StripUnicodeControlCodes(specialInput));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StripUnicodeControlCodes_PreservesMultiCodePoints()
|
||||
{
|
||||
// Turtles are a good example of multi-codepoint Unicode chars
|
||||
string specialInput = "♀ 🐢 🐢 ♂ ";
|
||||
Assert.AreEqual(specialInput, SoftwareKeyboardApplet.StripUnicodeControlCodes(specialInput));
|
||||
}
|
||||
}
|
||||
}
|
53
src/Ryujinx.Tests/Memory/MockMemoryManager.cs
Normal file
53
src/Ryujinx.Tests/Memory/MockMemoryManager.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using ARMeilleure.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Tests.Memory
|
||||
{
|
||||
internal class MockMemoryManager : IMemoryManager
|
||||
{
|
||||
public int AddressSpaceBits => throw new NotImplementedException();
|
||||
|
||||
public IntPtr PageTablePointer => throw new NotImplementedException();
|
||||
|
||||
public MemoryManagerType Type => MemoryManagerType.HostMappedUnsafe;
|
||||
|
||||
#pragma warning disable CS0067
|
||||
public event Action<ulong, ulong> UnmapEvent;
|
||||
#pragma warning restore CS0067
|
||||
|
||||
public ref T GetRef<T>(ulong va) where T : unmanaged
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsMapped(ulong va)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public T Read<T>(ulong va) where T : unmanaged
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public T ReadTracked<T>(ulong va) where T : unmanaged
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Write<T>(ulong va, T value) where T : unmanaged
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue