diff options
author | merry <git@mary.rs> | 2022-02-08 09:46:42 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-08 10:46:42 +0100 |
commit | 86b37d0ff7764ac62b1e9578b07a8b648a3bd55a (patch) | |
tree | f1500dddb5a4dad5c2d65a653e50b9a7dcee6287 /ARMeilleure/Instructions | |
parent | 863c5811903d9fe1020d966028ce6a030477be92 (diff) |
ARMeilleure: A32: Implement SHSUB8 and UHSUB8 (#3089)1.1.21
* ARMeilleure: A32: Implement UHSUB8
* ARMeilleure: A32: Implement SHSUB8
Diffstat (limited to 'ARMeilleure/Instructions')
-rw-r--r-- | ARMeilleure/Instructions/InstEmitAlu32.cs | 45 | ||||
-rw-r--r-- | ARMeilleure/Instructions/InstName.cs | 2 |
2 files changed, 47 insertions, 0 deletions
diff --git a/ARMeilleure/Instructions/InstEmitAlu32.cs b/ARMeilleure/Instructions/InstEmitAlu32.cs index 9aff0261..66b8a8a7 100644 --- a/ARMeilleure/Instructions/InstEmitAlu32.cs +++ b/ARMeilleure/Instructions/InstEmitAlu32.cs @@ -392,6 +392,11 @@ namespace ARMeilleure.Instructions EmitHadd8(context, false); } + public static void Shsub8(ArmEmitterContext context) + { + EmitHsub8(context, false); + } + public static void Ssat(ArmEmitterContext context) { OpCode32Sat op = (OpCode32Sat)context.CurrOp; @@ -482,6 +487,11 @@ namespace ARMeilleure.Instructions EmitHadd8(context, true); } + public static void Uhsub8(ArmEmitterContext context) + { + EmitHsub8(context, true); + } + public static void Usat(ArmEmitterContext context) { OpCode32Sat op = (OpCode32Sat)context.CurrOp; @@ -681,6 +691,41 @@ namespace ARMeilleure.Instructions 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) { OpCode32Sat op = (OpCode32Sat)context.CurrOp; diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs index 698979b9..3e016495 100644 --- a/ARMeilleure/Instructions/InstName.cs +++ b/ARMeilleure/Instructions/InstName.cs @@ -80,6 +80,7 @@ namespace ARMeilleure.Instructions Sbcs, Sbfm, Sdiv, + Shsub8, Smaddl, Smsubl, Smulh, @@ -546,6 +547,7 @@ namespace ARMeilleure.Instructions Tst, Ubfx, Uhadd8, + Uhsub8, Umaal, Umlal, Umull, |