Cpu: Implement VCVT (between floating-point and fixed-point) instruction (#5343)
* cpu: Implement VCVT (between floating-point and fixed-point) instruction Rebase, fix and superseed of https://github.com/Ryujinx/Ryujinx/pull/2915 (Since I only have little CPU knowledge, I hope I have done everything good) * Update Ptc.cs * Fix wrong cast * Rename tests * Addresses feedback Co-Authored-By: gdkchan <5624669+gdkchan@users.noreply.github.com> * Remove extra empty line --------- Co-authored-by: gdkchan <5624669+gdkchan@users.noreply.github.com>
This commit is contained in:
parent
2cdc82cb91
commit
9288ffd26d
5 changed files with 309 additions and 176 deletions
23
src/ARMeilleure/Decoders/OpCode32SimdCvtFFixed.cs
Normal file
23
src/ARMeilleure/Decoders/OpCode32SimdCvtFFixed.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32SimdCvtFFixed : OpCode32Simd
|
||||||
|
{
|
||||||
|
public int Fbits { get; protected set; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtFFixed(inst, address, opCode, false);
|
||||||
|
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtFFixed(inst, address, opCode, true);
|
||||||
|
|
||||||
|
public OpCode32SimdCvtFFixed(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
|
{
|
||||||
|
Opc = (opCode >> 8) & 0x1;
|
||||||
|
|
||||||
|
Size = Opc == 1 ? 0 : 2;
|
||||||
|
Fbits = 64 - ((opCode >> 16) & 0x3f);
|
||||||
|
|
||||||
|
if (DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm))
|
||||||
|
{
|
||||||
|
Instruction = InstDescriptor.Undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -918,6 +918,7 @@ namespace ARMeilleure.Decoders
|
||||||
SetAsimd("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
SetAsimd("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetAsimd("111100111x110000xxxx01010xx0xxxx", InstName.Vcnt, InstEmit32.Vcnt, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
SetAsimd("111100111x110000xxxx01010xx0xxxx", InstName.Vcnt, InstEmit32.Vcnt, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
|
||||||
SetAsimd("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32); // FP and integer, vector.
|
SetAsimd("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32); // FP and integer, vector.
|
||||||
|
SetAsimd("1111001x1x1xxxxxxxxx111x0xx1xxxx", InstName.Vcvt, InstEmit32.Vcvt_V_Fixed, OpCode32SimdCvtFFixed.Create, OpCode32SimdCvtFFixed.CreateT32); // Between floating point and fixed point, vector.
|
||||||
SetAsimd("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, OpCode32SimdDupElem.Create, OpCode32SimdDupElem.CreateT32);
|
SetAsimd("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, OpCode32SimdDupElem.Create, OpCode32SimdDupElem.CreateT32);
|
||||||
SetAsimd("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
SetAsimd("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, OpCode32SimdBinary.Create, OpCode32SimdBinary.CreateT32);
|
||||||
SetAsimd("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, OpCode32SimdExt.Create, OpCode32SimdExt.CreateT32);
|
SetAsimd("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, OpCode32SimdExt.Create, OpCode32SimdExt.CreateT32);
|
||||||
|
|
|
@ -114,6 +114,35 @@ namespace ARMeilleure.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Vcvt_V_Fixed(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32SimdCvtFFixed op = (OpCode32SimdCvtFFixed)context.CurrOp;
|
||||||
|
|
||||||
|
var toFixed = op.Opc == 1;
|
||||||
|
int fracBits = op.Fbits;
|
||||||
|
var unsigned = op.U;
|
||||||
|
|
||||||
|
if (toFixed) // F32 to S32 or U32 (fixed)
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpF32(context, (op1) =>
|
||||||
|
{
|
||||||
|
var scaledValue = context.Multiply(op1, ConstF(MathF.Pow(2f, fracBits)));
|
||||||
|
MethodInfo info = unsigned ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)) : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32));
|
||||||
|
|
||||||
|
return context.Call(info, scaledValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else // S32 or U32 (fixed) to F32
|
||||||
|
{
|
||||||
|
EmitVectorUnaryOpI32(context, (op1) =>
|
||||||
|
{
|
||||||
|
var floatValue = unsigned ? context.ConvertToFPUI(OperandType.FP32, op1) : context.ConvertToFP(OperandType.FP32, op1);
|
||||||
|
|
||||||
|
return context.Multiply(floatValue, ConstF(1f / MathF.Pow(2f, fracBits)));
|
||||||
|
}, !unsigned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Vcvt_FD(ArmEmitterContext context)
|
public static void Vcvt_FD(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 5292; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 5343; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
|
|
@ -426,6 +426,86 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
CompareAgainstUnicorn();
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise, Description("VCVT.I32.F32 <Vd>, <Vm>, #<fbits>")]
|
||||||
|
public void Vcvt_V_Fixed_F32_I32([Values(0u, 1u, 2u, 3u)] uint vd,
|
||||||
|
[Values(0u, 1u, 2u, 3u)] uint vm,
|
||||||
|
[ValueSource(nameof(_1S_F_))][Random(RndCnt)] ulong s0,
|
||||||
|
[ValueSource(nameof(_1S_F_))][Random(RndCnt)] ulong s1,
|
||||||
|
[ValueSource(nameof(_1S_F_))][Random(RndCnt)] ulong s2,
|
||||||
|
[ValueSource(nameof(_1S_F_))][Random(RndCnt)] ulong s3,
|
||||||
|
[Random(32u, 63u, 1)] uint fixImm,
|
||||||
|
[Values] bool unsigned,
|
||||||
|
[Values] bool q)
|
||||||
|
{
|
||||||
|
uint opcode = 0xF2800F10u; // VCVT.U32.F32 D0, D0, #0
|
||||||
|
|
||||||
|
if (q)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 6;
|
||||||
|
vm <<= 1;
|
||||||
|
vd <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unsigned)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode |= ((vm & 0x10) << 1);
|
||||||
|
opcode |= ((vm & 0xf) << 0);
|
||||||
|
|
||||||
|
opcode |= ((vd & 0x10) << 18);
|
||||||
|
opcode |= ((vd & 0xf) << 12);
|
||||||
|
|
||||||
|
opcode |= (fixImm & 0x3f) << 16;
|
||||||
|
|
||||||
|
var v0 = new V128((uint)s0, (uint)s1, (uint)s2, (uint)s3);
|
||||||
|
|
||||||
|
SingleOpcode(opcode, v0: v0);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise, Description("VCVT.F32.I32 <Vd>, <Vm>, #<fbits>")]
|
||||||
|
public void Vcvt_V_Fixed_I32_F32([Values(0u, 1u, 2u, 3u)] uint vd,
|
||||||
|
[Values(0u, 1u, 2u, 3u)] uint vm,
|
||||||
|
[ValueSource(nameof(_1S_))][Random(RndCnt)] uint s0,
|
||||||
|
[ValueSource(nameof(_1S_))][Random(RndCnt)] uint s1,
|
||||||
|
[ValueSource(nameof(_1S_))][Random(RndCnt)] uint s2,
|
||||||
|
[ValueSource(nameof(_1S_))][Random(RndCnt)] uint s3,
|
||||||
|
[Range(32u, 63u, 1)] uint fixImm,
|
||||||
|
[Values] bool unsigned,
|
||||||
|
[Values] bool q)
|
||||||
|
{
|
||||||
|
uint opcode = 0xF2800E10u; // VCVT.F32.U32 D0, D0, #0
|
||||||
|
|
||||||
|
if (q)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 6;
|
||||||
|
vm <<= 1;
|
||||||
|
vd <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unsigned)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode |= ((vm & 0x10) << 1);
|
||||||
|
opcode |= ((vm & 0xf) << 0);
|
||||||
|
|
||||||
|
opcode |= ((vd & 0x10) << 18);
|
||||||
|
opcode |= ((vd & 0xf) << 12);
|
||||||
|
|
||||||
|
opcode |= (fixImm & 0x3f) << 16;
|
||||||
|
|
||||||
|
var v0 = new V128(s0, s1, s2, s3);
|
||||||
|
|
||||||
|
SingleOpcode(opcode, v0: v0);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue