mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-03-14 17:00:17 +00:00
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:
parent
284272854b
commit
43feb68b11
8 changed files with 197 additions and 3 deletions
10
ARMeilleure/Decoders/IOpCode32AluRsReg.cs
Normal file
10
ARMeilleure/Decoders/IOpCode32AluRsReg.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32AluRsReg : IOpCode32Alu
|
||||
{
|
||||
int Rm { get; }
|
||||
int Rs { get; }
|
||||
|
||||
ShiftType ShiftType { get; }
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32AluRsReg : OpCode32Alu
|
||||
class OpCode32AluRsReg : OpCode32Alu, IOpCode32AluRsReg
|
||||
{
|
||||
public int Rm { get; }
|
||||
public int Rs { get; }
|
||||
|
|
26
ARMeilleure/Decoders/OpCodeT16AluImmZero.cs
Normal file
26
ARMeilleure/Decoders/OpCodeT16AluImmZero.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
22
ARMeilleure/Decoders/OpCodeT16AluRegLow.cs
Normal file
22
ARMeilleure/Decoders/OpCodeT16AluRegLow.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
29
ARMeilleure/Decoders/OpCodeT16ShiftReg.cs
Normal file
29
ARMeilleure/Decoders/OpCodeT16ShiftReg.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue