forked from Mirror/Ryujinx
ARMeilleure: A32: Implement SHSUB8 and UHSUB8 (#3089)
* ARMeilleure: A32: Implement UHSUB8 * ARMeilleure: A32: Implement SHSUB8
This commit is contained in:
parent
863c581190
commit
86b37d0ff7
4 changed files with 87 additions and 0 deletions
|
@ -734,6 +734,7 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<0111101xxxxxxxxxxxxxx101xxxx", InstName.Sbfx, InstEmit32.Sbfx, OpCode32AluBf.Create);
|
SetA32("<<<<0111101xxxxxxxxxxxxxx101xxxx", InstName.Sbfx, InstEmit32.Sbfx, OpCode32AluBf.Create);
|
||||||
SetA32("<<<<01110001xxxx1111xxxx0001xxxx", InstName.Sdiv, InstEmit32.Sdiv, OpCode32AluMla.Create);
|
SetA32("<<<<01110001xxxx1111xxxx0001xxxx", InstName.Sdiv, InstEmit32.Sdiv, OpCode32AluMla.Create);
|
||||||
SetA32("<<<<01100011xxxxxxxx11111001xxxx", InstName.Shadd8, InstEmit32.Shadd8, OpCode32AluReg.Create);
|
SetA32("<<<<01100011xxxxxxxx11111001xxxx", InstName.Shadd8, InstEmit32.Shadd8, OpCode32AluReg.Create);
|
||||||
|
SetA32("<<<<01100011xxxxxxxx11111111xxxx", InstName.Shsub8, InstEmit32.Shsub8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<00010000xxxxxxxxxxxx1xx0xxxx", InstName.Smla__, InstEmit32.Smla__, OpCode32AluMla.Create);
|
SetA32("<<<<00010000xxxxxxxxxxxx1xx0xxxx", InstName.Smla__, InstEmit32.Smla__, OpCode32AluMla.Create);
|
||||||
SetA32("<<<<0000111xxxxxxxxxxxxx1001xxxx", InstName.Smlal, InstEmit32.Smlal, OpCode32AluUmull.Create);
|
SetA32("<<<<0000111xxxxxxxxxxxxx1001xxxx", InstName.Smlal, InstEmit32.Smlal, OpCode32AluUmull.Create);
|
||||||
SetA32("<<<<00010100xxxxxxxxxxxx1xx0xxxx", InstName.Smlal__, InstEmit32.Smlal__, OpCode32AluUmull.Create);
|
SetA32("<<<<00010100xxxxxxxxxxxx1xx0xxxx", InstName.Smlal__, InstEmit32.Smlal__, OpCode32AluUmull.Create);
|
||||||
|
@ -782,6 +783,7 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx, InstEmit32.Ubfx, OpCode32AluBf.Create);
|
SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx, InstEmit32.Ubfx, OpCode32AluBf.Create);
|
||||||
SetA32("<<<<01110011xxxx1111xxxx0001xxxx", InstName.Udiv, InstEmit32.Udiv, OpCode32AluMla.Create);
|
SetA32("<<<<01110011xxxx1111xxxx0001xxxx", InstName.Udiv, InstEmit32.Udiv, OpCode32AluMla.Create);
|
||||||
SetA32("<<<<01100111xxxxxxxx11111001xxxx", InstName.Uhadd8, InstEmit32.Uhadd8, OpCode32AluReg.Create);
|
SetA32("<<<<01100111xxxxxxxx11111001xxxx", InstName.Uhadd8, InstEmit32.Uhadd8, OpCode32AluReg.Create);
|
||||||
|
SetA32("<<<<01100111xxxxxxxx11111111xxxx", InstName.Uhsub8, InstEmit32.Uhsub8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal, InstEmit32.Umaal, OpCode32AluUmull.Create);
|
SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal, InstEmit32.Umaal, OpCode32AluUmull.Create);
|
||||||
SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal, InstEmit32.Umlal, OpCode32AluUmull.Create);
|
SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal, InstEmit32.Umlal, OpCode32AluUmull.Create);
|
||||||
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create);
|
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create);
|
||||||
|
|
|
@ -392,6 +392,11 @@ namespace ARMeilleure.Instructions
|
||||||
EmitHadd8(context, false);
|
EmitHadd8(context, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Shsub8(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitHsub8(context, false);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Ssat(ArmEmitterContext context)
|
public static void Ssat(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
||||||
|
@ -482,6 +487,11 @@ namespace ARMeilleure.Instructions
|
||||||
EmitHadd8(context, true);
|
EmitHadd8(context, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Uhsub8(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitHsub8(context, true);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Usat(ArmEmitterContext context)
|
public static void Usat(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
||||||
|
@ -681,6 +691,41 @@ namespace ARMeilleure.Instructions
|
||||||
SetIntA32(context, op.Rd, res);
|
SetIntA32(context, op.Rd, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitHsub8(ArmEmitterContext context, bool unsigned)
|
||||||
|
{
|
||||||
|
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
|
Operand left, right, carry, res;
|
||||||
|
|
||||||
|
// This relies on the equality x-y == (x^y) - (((x^y)&y) << 1).
|
||||||
|
// Note that x^y always contains the LSB of the result.
|
||||||
|
// Since we want to calculate (x+y)/2, we can instead calculate ((x^y)>>1) - ((x^y)&y).
|
||||||
|
|
||||||
|
carry = context.BitwiseExclusiveOr(m, n);
|
||||||
|
left = context.ShiftRightUI(carry, Const(1));
|
||||||
|
right = context.BitwiseAnd(carry, m);
|
||||||
|
|
||||||
|
// We must now perform a partitioned subtraction.
|
||||||
|
// We can do this because minuend contains 7 bit fields.
|
||||||
|
// We use the extra bit in minuend as a bit to borrow from; we set this bit.
|
||||||
|
// We invert this bit at the end as this tells us if that bit was borrowed from.
|
||||||
|
|
||||||
|
res = context.BitwiseOr(left, Const(0x80808080));
|
||||||
|
res = context.Subtract(res, right);
|
||||||
|
res = context.BitwiseExclusiveOr(res, Const(0x80808080));
|
||||||
|
|
||||||
|
if (!unsigned)
|
||||||
|
{
|
||||||
|
// We then sign extend the result into this bit.
|
||||||
|
carry = context.BitwiseAnd(carry, Const(0x80808080));
|
||||||
|
res = context.BitwiseExclusiveOr(res, carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rd, res);
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitSat(ArmEmitterContext context, int intMin, int intMax)
|
private static void EmitSat(ArmEmitterContext context, int intMin, int intMax)
|
||||||
{
|
{
|
||||||
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
||||||
|
|
|
@ -80,6 +80,7 @@ namespace ARMeilleure.Instructions
|
||||||
Sbcs,
|
Sbcs,
|
||||||
Sbfm,
|
Sbfm,
|
||||||
Sdiv,
|
Sdiv,
|
||||||
|
Shsub8,
|
||||||
Smaddl,
|
Smaddl,
|
||||||
Smsubl,
|
Smsubl,
|
||||||
Smulh,
|
Smulh,
|
||||||
|
@ -546,6 +547,7 @@ namespace ARMeilleure.Instructions
|
||||||
Tst,
|
Tst,
|
||||||
Ubfx,
|
Ubfx,
|
||||||
Uhadd8,
|
Uhadd8,
|
||||||
|
Uhsub8,
|
||||||
Umaal,
|
Umaal,
|
||||||
Umlal,
|
Umlal,
|
||||||
Umull,
|
Umull,
|
||||||
|
|
|
@ -96,6 +96,25 @@ namespace Ryujinx.Tests.Cpu
|
||||||
CompareAgainstUnicorn();
|
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]
|
[Test, Pairwise]
|
||||||
public void Ssat_Usat([ValueSource("_Ssat_Usat_")] uint opcode,
|
public void Ssat_Usat([ValueSource("_Ssat_Usat_")] uint opcode,
|
||||||
[Values(0u, 0xdu)] uint rd,
|
[Values(0u, 0xdu)] uint rd,
|
||||||
|
@ -149,6 +168,25 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
CompareAgainstUnicorn();
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise]
|
||||||
|
public void Uhsub8([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 = 0xE6700FF0u; // UHSUB8 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();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue