T16: Implement ANDS, EORS, LSLS, LSRS, ASRS, ADCS, SBCS, RORS, TST, NEGS, CMP, CMN, ORRS, MULS, BICS, MVNS (low registers)

This commit is contained in:
merry 2022-02-10 20:57:29 +00:00
parent 284272854b
commit 43feb68b11
8 changed files with 197 additions and 3 deletions

View file

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluRsReg : IOpCode32Alu
{
int Rm { get; }
int Rs { get; }
ShiftType ShiftType { get; }
}
}

View file

@ -1,6 +1,6 @@
namespace ARMeilleure.Decoders
{
class OpCode32AluRsReg : OpCode32Alu
class OpCode32AluRsReg : OpCode32Alu, IOpCode32AluRsReg
{
public int Rm { get; }
public int Rs { get; }

View file

@ -0,0 +1,26 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16AluImmZero : OpCodeT16, IOpCode32AluImm
{
public int Rd { get; }
public int Rn { get; }
public bool SetFlags { get; }
public int Immediate { get; }
public bool IsRotated { get; }
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode, bool inITBlock) => new OpCodeT16AluImmZero(inst, address, opCode, inITBlock);
public OpCodeT16AluImmZero(InstDescriptor inst, ulong address, int opCode, bool inITBlock) : base(inst, address, opCode, inITBlock)
{
Rd = (opCode >> 0) & 0x7;
Rn = (opCode >> 3) & 0x7;
Immediate = 0;
IsRotated = false;
SetFlags = !inITBlock;
}
}
}

View file

@ -0,0 +1,22 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16AluRegLow : OpCodeT16, IOpCode32AluReg
{
public int Rm { get; }
public int Rd { get; }
public int Rn { get; }
public bool SetFlags { get; }
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode, bool inITBlock) => new OpCodeT16AluRegLow(inst, address, opCode, inITBlock);
public OpCodeT16AluRegLow(InstDescriptor inst, ulong address, int opCode, bool inITBlock) : base(inst, address, opCode, inITBlock)
{
Rd = (opCode >> 0) & 0x7;
Rn = (opCode >> 0) & 0x7;
Rm = (opCode >> 3) & 0x7;
SetFlags = !inITBlock;
}
}
}

View file

@ -0,0 +1,29 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16ShiftReg : OpCodeT16, IOpCode32AluRsReg
{
public int Rm { get; }
public int Rs { get; }
public int Rd { get; }
public int Rn { get; }
public ShiftType ShiftType { get; }
public bool SetFlags { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode, bool inITBlock) => new OpCodeT16ShiftReg(inst, address, opCode, inITBlock);
public OpCodeT16ShiftReg(InstDescriptor inst, ulong address, int opCode, bool inITBlock) : base(inst, address, opCode, inITBlock)
{
Rd = (opCode >> 0) & 7;
Rm = (opCode >> 0) & 7;
Rn = (opCode >> 3) & 7;
Rs = (opCode >> 3) & 7;
ShiftType = (ShiftType)(((opCode >> 6) & 1) | ((opCode >> 7) & 2));
SetFlags = !inITBlock;
}
}
}

View file

@ -983,6 +983,22 @@ namespace ARMeilleure.Decoders
SetT16("00101xxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluImm8.Create);
SetT16("00110xxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AluImm8.Create);
SetT16("00111xxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AluImm8.Create);
SetT16("0100000000xxxxxx", InstName.And, InstEmit32.And, OpCodeT16AluRegLow.Create);
SetT16("0100000001xxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT16AluRegLow.Create);
SetT16("0100000010xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
SetT16("0100000011xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
SetT16("0100000100xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
SetT16("0100000101xxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT16AluRegLow.Create);
SetT16("0100000110xxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT16AluRegLow.Create);
SetT16("0100000111xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
SetT16("0100001000xxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT16AluRegLow.Create);
SetT16("0100001001xxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT16AluImmZero.Create);
SetT16("0100001010xxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegLow.Create);
SetT16("0100001011xxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT16AluRegLow.Create);
SetT16("0100001100xxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT16AluRegLow.Create);
SetT16("0100001101xxxxxx", InstName.Mul, InstEmit32.Mul, OpCodeT16AluRegLow.Create);
SetT16("0100001110xxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT16AluRegLow.Create);
SetT16("0100001111xxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT16AluRegLow.Create);
SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
#endregion

View file

@ -196,7 +196,7 @@ namespace ARMeilleure.Instructions
case OpCode32AluImm16 op: return Const(op.Immediate);
case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
case OpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
@ -303,7 +303,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));

View file

@ -9,6 +9,11 @@ namespace Ryujinx.Tests.Cpu
{
private const int RndCnt = 2;
public static uint RotateRight(uint value, int count)
{
return (value >> count) | (value << (32 - count));
}
[Test, Pairwise]
public void ShiftImm([Range(0u, 2u)] uint shiftType, [Range(1u, 0x1fu)] uint shiftImm, [Random(RndCnt)] uint w1, [Random(RndCnt)] uint w2)
{
@ -116,5 +121,91 @@ namespace Ryujinx.Tests.Cpu
goto cmpFlags;
}
}
[Test, Pairwise]
public void AluRegLow([Range(0u, 0xfu)] uint op, [Random(RndCnt)] uint w1, [Random(RndCnt)] uint w2)
{
uint opcode = 0x4000; // ANDS <Rdn>, <Rm>
uint rd = 1;
uint rm = 2;
opcode |= ((rd & 7) << 0) | ((rm & 7) << 3) | ((op & 0xf) << 6);
SingleThumbOpcode((ushort)opcode, r1: w1, r2: w2, runUnicorn: false);
uint shift = w2 & 0xff;
switch (op)
{
case 0:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1 & w2));
break;
case 1:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1 ^ w2));
break;
case 2:
Assert.That(GetContext().GetX(1), Is.EqualTo(shift >= 32 ? 0 : (uint)(w1 << (int)shift)));
break;
case 3:
Assert.That(GetContext().GetX(1), Is.EqualTo(shift >= 32 ? 0 : (uint)(w1 >> (int)shift)));
break;
case 4:
Assert.That(GetContext().GetX(1), Is.EqualTo(shift >= 32 ? (uint)((int)w1 >> 31) : (uint)((int)w1 >> (int)shift)));
break;
case 5:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1 + w2));
break;
case 6:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1 + ~w2));
break;
case 7:
Assert.That(GetContext().GetX(1), Is.EqualTo(RotateRight(w1, (int)shift & 31)));
break;
case 8:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1));
{
uint result = w1 & w2;
Assert.That(GetContext().GetPstateFlag(PState.NFlag), Is.EqualTo((result >> 31) != 0));
Assert.That(GetContext().GetPstateFlag(PState.ZFlag), Is.EqualTo(result == 0));
}
break;
case 9:
Assert.That(GetContext().GetX(1), Is.EqualTo((uint)-w2));
break;
case 10:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1));
{
uint result = w1 - w2;
uint overflow = (result ^ w1) & (w1 ^ w2);
Assert.That(GetContext().GetPstateFlag(PState.NFlag), Is.EqualTo((result >> 31) != 0));
Assert.That(GetContext().GetPstateFlag(PState.ZFlag), Is.EqualTo(result == 0));
Assert.That(GetContext().GetPstateFlag(PState.CFlag), Is.EqualTo(w1 >= w2));
Assert.That(GetContext().GetPstateFlag(PState.VFlag), Is.EqualTo((overflow >> 31) != 0));
}
break;
case 11:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1));
{
uint result = w1 + w2;
uint overflow = (result ^ w1) & ~(w1 ^ w2);
Assert.That(GetContext().GetPstateFlag(PState.NFlag), Is.EqualTo((result >> 31) != 0));
Assert.That(GetContext().GetPstateFlag(PState.ZFlag), Is.EqualTo(result == 0));
Assert.That(GetContext().GetPstateFlag(PState.CFlag), Is.EqualTo(result < w1));
Assert.That(GetContext().GetPstateFlag(PState.VFlag), Is.EqualTo((overflow >> 31) != 0));
}
break;
case 12:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1 | w2));
break;
case 13:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1 * w2));
break;
case 14:
Assert.That(GetContext().GetX(1), Is.EqualTo(w1 & ~w2));
break;
case 15:
Assert.That(GetContext().GetX(1), Is.EqualTo(~w2));
break;
}
}
}
}