ARMeilleure: Thumb support (All T16 instructions) (#3105)
* Decoders: Add InITBlock argument * OpCodeTable: Minor cleanup * OpCodeTable: Remove existing thumb instruction implementations * OpCodeTable: Prepare for thumb instructions * OpCodeTables: Improve thumb fast lookup * Tests: Prepare for thumb tests * T16: Implement BX * T16: Implement LSL/LSR/ASR (imm) * T16: Implement ADDS, SUBS (reg) * T16: Implement ADDS, SUBS (3-bit immediate) * T16: Implement MOVS, CMP, ADDS, SUBS (8-bit immediate) * T16: Implement ANDS, EORS, LSLS, LSRS, ASRS, ADCS, SBCS, RORS, TST, NEGS, CMP, CMN, ORRS, MULS, BICS, MVNS (low registers) * T16: Implement ADD, CMP, MOV (high reg) * T16: Implement BLX (reg) * T16: Implement LDR (literal) * T16: Implement {LDR,STR}{,H,B,SB,SH} (register) * T16: Implement {LDR,STR}{,B,H} (immediate) * T16: Implement LDR/STR (SP) * T16: Implement ADR * T16: Implement Add to SP (immediate) * T16: Implement ADD/SUB (SP) * T16: Implement SXTH, SXTB, UXTH, UTXB * T16: Implement CBZ, CBNZ * T16: Implement PUSH, POP * T16: Implement REV, REV16, REVSH * T16: Implement NOP * T16: Implement LDM, STM * T16: Implement SVC * T16: Implement B (conditional) * T16: Implement B (unconditional) * T16: Implement IT * fixup! T16: Implement ADD/SUB (SP) * fixup! T16: Implement Add to SP (immediate) * fixup! T16: Implement IT * CpuTestThumb: Add randomized tests * Remove inITBlock argument * Address nits * Use index to handle IfThenBlockState * Reduce line noise * fixup * nit
This commit is contained in:
parent
868919e101
commit
98e05ee4b7
57 changed files with 1852 additions and 102 deletions
|
@ -20,7 +20,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.Add(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
|
@ -44,7 +44,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
res = context.Add(res, carry);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
|
@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.BitwiseAnd(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.BitwiseAnd(n, context.BitwiseNot(m));
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.BitwiseExclusiveOr(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand m = GetAluM(context);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, m);
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.Multiply(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.BitwiseNot(m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.BitwiseOr(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
res = context.Subtract(res, borrow);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
|
@ -335,7 +335,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.Subtract(m, n);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
|
@ -359,7 +359,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
res = context.Subtract(res, borrow);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
|
@ -420,7 +420,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.Subtract(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
|
@ -836,7 +836,7 @@ namespace ARMeilleure.Instructions
|
|||
{
|
||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||
|
||||
EmitGenericAluStoreA32(context, op.Rd, op.SetFlags, value);
|
||||
EmitGenericAluStoreA32(context, op.Rd, ShouldSetFlags(context), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,18 @@ namespace ARMeilleure.Instructions
|
|||
{
|
||||
static class InstEmitAluHelper
|
||||
{
|
||||
public static bool ShouldSetFlags(ArmEmitterContext context)
|
||||
{
|
||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||
|
||||
if (op.SetFlags == null)
|
||||
{
|
||||
return !context.IsInIfThenBlock;
|
||||
}
|
||||
|
||||
return op.SetFlags.Value;
|
||||
}
|
||||
|
||||
public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
|
||||
{
|
||||
SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
|
||||
|
@ -183,9 +195,9 @@ namespace ARMeilleure.Instructions
|
|||
switch (context.CurrOp)
|
||||
{
|
||||
// ARM32.
|
||||
case OpCode32AluImm op:
|
||||
case IOpCode32AluImm op:
|
||||
{
|
||||
if (op.SetFlags && op.IsRotated)
|
||||
if (ShouldSetFlags(context) && op.IsRotated)
|
||||
{
|
||||
SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31));
|
||||
}
|
||||
|
@ -195,10 +207,8 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
case OpCode32AluImm16 op: return Const(op.Immediate);
|
||||
|
||||
case OpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||
case OpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
||||
|
||||
case OpCodeT16AluImm8 op: return Const(op.Immediate);
|
||||
case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||
case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
||||
|
||||
case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
|
||||
|
||||
|
@ -249,7 +259,7 @@ namespace ARMeilleure.Instructions
|
|||
}
|
||||
|
||||
// ARM32 helpers.
|
||||
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32AluRsImm op, bool setCarry)
|
||||
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, IOpCode32AluRsImm op, bool setCarry)
|
||||
{
|
||||
Operand m = GetIntA32(context, op.Rm);
|
||||
|
||||
|
@ -267,7 +277,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
if (shift != 0)
|
||||
{
|
||||
setCarry &= op.SetFlags;
|
||||
setCarry &= ShouldSetFlags(context);
|
||||
|
||||
switch (op.ShiftType)
|
||||
{
|
||||
|
@ -305,7 +315,7 @@ namespace ARMeilleure.Instructions
|
|||
return shift;
|
||||
}
|
||||
|
||||
public static Operand GetMShiftedByReg(ArmEmitterContext context, OpCode32AluRsReg op, bool setCarry)
|
||||
public static Operand GetMShiftedByReg(ArmEmitterContext context, IOpCode32AluRsReg op, bool setCarry)
|
||||
{
|
||||
Operand m = GetIntA32(context, op.Rm);
|
||||
Operand s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs));
|
||||
|
@ -314,7 +324,7 @@ namespace ARMeilleure.Instructions
|
|||
Operand zeroResult = m;
|
||||
Operand shiftResult = m;
|
||||
|
||||
setCarry &= op.SetFlags;
|
||||
setCarry &= ShouldSetFlags(context);
|
||||
|
||||
switch (op.ShiftType)
|
||||
{
|
||||
|
|
|
@ -20,11 +20,11 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
private static void EmitExceptionCall(ArmEmitterContext context, string name)
|
||||
{
|
||||
OpCode32Exception op = (OpCode32Exception)context.CurrOp;
|
||||
IOpCode32Exception op = (IOpCode32Exception)context.CurrOp;
|
||||
|
||||
context.StoreToContext();
|
||||
|
||||
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
|
||||
context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
|
||||
|
||||
context.LoadFromContext();
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
|
|||
bool isThumb = IsThumb(context.CurrOp);
|
||||
|
||||
uint currentPc = isThumb
|
||||
? pc | 1
|
||||
? (pc - 2) | 1
|
||||
: pc - 4;
|
||||
|
||||
SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
|
||||
|
@ -80,5 +80,32 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm);
|
||||
}
|
||||
|
||||
public static void Cbnz(ArmEmitterContext context) => EmitCb(context, onNotZero: true);
|
||||
public static void Cbz(ArmEmitterContext context) => EmitCb(context, onNotZero: false);
|
||||
|
||||
private static void EmitCb(ArmEmitterContext context, bool onNotZero)
|
||||
{
|
||||
OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;
|
||||
|
||||
Operand value = GetIntOrZR(context, op.Rn);
|
||||
Operand lblTarget = context.GetLabel((ulong)op.Immediate);
|
||||
|
||||
if (onNotZero)
|
||||
{
|
||||
context.BranchIfTrue(lblTarget, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.BranchIfFalse(lblTarget, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void It(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeT16IfThen op = (OpCodeT16IfThen)context.CurrOp;
|
||||
|
||||
context.SetIfThenBlockState(op.IfThenBlockConds);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static void Ldm(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
||||
IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
|
||||
|
||||
Operand n = GetIntA32(context, op.Rn);
|
||||
|
||||
|
@ -95,7 +95,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static void Stm(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
||||
IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
|
||||
|
||||
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
||||
|
||||
|
@ -151,7 +151,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
|
||||
{
|
||||
OpCode32Mem op = (OpCode32Mem)context.CurrOp;
|
||||
IOpCode32Mem op = (IOpCode32Mem)context.CurrOp;
|
||||
|
||||
Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn));
|
||||
Operand m = GetMemM(context, setCarry: false);
|
||||
|
@ -255,5 +255,11 @@ namespace ARMeilleure.Instructions
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Adr(ArmEmitterContext context)
|
||||
{
|
||||
IOpCode32Adr op = (IOpCode32Adr)context.CurrOp;
|
||||
SetIntA32(context, op.Rd, Const(op.Immediate));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -549,9 +549,9 @@ namespace ARMeilleure.Instructions
|
|||
{
|
||||
case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||
|
||||
case OpCode32MemReg op: return GetIntA32(context, op.Rm);
|
||||
case IOpCode32MemReg op: return GetIntA32(context, op.Rm);
|
||||
|
||||
case OpCode32Mem op: return Const(op.Immediate);
|
||||
case IOpCode32Mem op: return Const(op.Immediate);
|
||||
|
||||
case OpCode32SimdMemImm op: return Const(op.Immediate);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand res = context.Add(a, context.Multiply(n, m));
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
@ -250,13 +250,13 @@ namespace ARMeilleure.Instructions
|
|||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||
Operand lo = context.ConvertI64ToI32(res);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
||||
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||
}
|
||||
|
||||
public static void Smulw_(ArmEmitterContext context)
|
||||
|
@ -320,13 +320,13 @@ namespace ARMeilleure.Instructions
|
|||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||
Operand lo = context.ConvertI64ToI32(res);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
||||
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||
}
|
||||
|
||||
private static void EmitMlal(ArmEmitterContext context, bool signed)
|
||||
|
@ -356,13 +356,13 @@ namespace ARMeilleure.Instructions
|
|||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||
Operand lo = context.ConvertI64ToI32(res);
|
||||
|
||||
if (op.SetFlags)
|
||||
if (ShouldSetFlags(context))
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
}
|
||||
|
||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
||||
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||
}
|
||||
|
||||
private static void UpdateQFlag(ArmEmitterContext context, Operand q)
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace ARMeilleure.Instructions
|
|||
Extr,
|
||||
Hint,
|
||||
Isb,
|
||||
It,
|
||||
Ldar,
|
||||
Ldaxp,
|
||||
Ldaxr,
|
||||
|
@ -512,6 +513,8 @@ namespace ARMeilleure.Instructions
|
|||
Mvn,
|
||||
Pkh,
|
||||
Pld,
|
||||
Pop,
|
||||
Push,
|
||||
Rev,
|
||||
Revsh,
|
||||
Rsb,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue