Skip to content

Commit

Permalink
Add ADD (zx imm12), NOP, MOV (rs), LDA, TBB, TBH, MOV (zx imm16) and …
Browse files Browse the repository at this point in the history
…CLZ thumb instructions (#3683)

* Add ADD (zx imm12), NOP, MOV (register shifted), LDA, TBB, TBH, MOV (zx imm16) and CLZ thumb instructions, fix LDRD, STRD, CBZ, CBNZ and BLX (reg)

* Bump PPTC version
  • Loading branch information
gdkchan committed Sep 10, 2022
1 parent db45688 commit c64524a
Show file tree
Hide file tree
Showing 16 changed files with 185 additions and 17 deletions.
7 changes: 7 additions & 0 deletions ARMeilleure/Decoders/Decoder.cs
Expand Up @@ -251,6 +251,13 @@ private static bool IsAarch32UnconditionalBranch(OpCode opCode)
return false;
}

// Compare and branch instructions are always conditional.
if (opCode.Instruction.Name == InstName.Cbz ||
opCode.Instruction.Name == InstName.Cbnz)
{
return false;
}

// Note: On ARM32, most instructions have conditional execution,
// so there's no "Always" (unconditional) branch like on ARM64.
// We need to check if the condition is "Always" instead.
Expand Down
2 changes: 1 addition & 1 deletion ARMeilleure/Decoders/DecoderHelper.cs
Expand Up @@ -151,7 +151,7 @@ public static long DecodeImmS14_2(int opCode)

public static bool VectorArgumentsInvalid(bool q, params int[] args)
{
if (q)
if (q)
{
for (int i = 0; i < args.Length; i++)
{
Expand Down
1 change: 1 addition & 0 deletions ARMeilleure/Decoders/IOpCode32Mem.cs
Expand Up @@ -3,6 +3,7 @@ namespace ARMeilleure.Decoders
interface IOpCode32Mem : IOpCode32
{
int Rt { get; }
int Rt2 => Rt | 1;
int Rn { get; }

bool WBack { get; }
Expand Down
3 changes: 1 addition & 2 deletions ARMeilleure/Decoders/OpCodeT16Adr.cs
Expand Up @@ -4,14 +4,13 @@ class OpCodeT16Adr : OpCodeT16, IOpCode32Adr
{
public int Rd { get; }

public bool Add => true;
public int Immediate { get; }

public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Adr(inst, address, opCode);

public OpCodeT16Adr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 8) & 7;
Rd = (opCode >> 8) & 7;

int imm = (opCode & 0xff) << 2;
Immediate = (int)(GetPc() & 0xfffffffc) + imm;
Expand Down
16 changes: 16 additions & 0 deletions ARMeilleure/Decoders/OpCodeT32AluImm12.cs
@@ -0,0 +1,16 @@
namespace ARMeilleure.Decoders
{
class OpCodeT32AluImm12 : OpCodeT32Alu, IOpCode32AluImm
{
public int Immediate { get; }

public bool IsRotated => false;

public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluImm12(inst, address, opCode);

public OpCodeT32AluImm12(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Immediate = (opCode & 0xff) | ((opCode >> 4) & 0x700) | ((opCode >> 15) & 0x800);
}
}
}
14 changes: 14 additions & 0 deletions ARMeilleure/Decoders/OpCodeT32AluReg.cs
@@ -0,0 +1,14 @@
namespace ARMeilleure.Decoders
{
class OpCodeT32AluReg : OpCodeT32Alu, IOpCode32AluReg
{
public int Rm { get; }

public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluReg(inst, address, opCode);

public OpCodeT32AluReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = (opCode >> 0) & 0xf;
}
}
}
2 changes: 1 addition & 1 deletion ARMeilleure/Decoders/OpCodeT32MemImm8D.cs
Expand Up @@ -23,7 +23,7 @@ public OpCodeT32MemImm8D(InstDescriptor inst, ulong address, int opCode) : base(
Add = ((opCode >> 23) & 1) != 0;
WBack = ((opCode >> 21) & 1) != 0;

Immediate = opCode & 0xff;
Immediate = (opCode & 0xff) << 2;

IsLoad = ((opCode >> 20) & 1) != 0;
}
Expand Down
19 changes: 19 additions & 0 deletions ARMeilleure/Decoders/OpCodeT32MovImm16.cs
@@ -0,0 +1,19 @@
using ARMeilleure.Common;
using System.Runtime.Intrinsics;

namespace ARMeilleure.Decoders
{
class OpCodeT32MovImm16 : OpCodeT32Alu, IOpCode32AluImm
{
public int Immediate { get; }

public bool IsRotated => false;

public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MovImm16(inst, address, opCode);

public OpCodeT32MovImm16(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Immediate = (opCode & 0xff) | ((opCode >> 4) & 0x700) | ((opCode >> 15) & 0x800) | ((opCode >> 4) & 0xf000);
}
}
}
19 changes: 19 additions & 0 deletions ARMeilleure/Decoders/OpCodeT32ShiftReg.cs
@@ -0,0 +1,19 @@
namespace ARMeilleure.Decoders
{
class OpCodeT32ShiftReg : OpCodeT32Alu, IOpCode32AluRsReg
{
public int Rm => Rn;
public int Rs { get; }

public ShiftType ShiftType { get; }

public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32ShiftReg(inst, address, opCode);

public OpCodeT32ShiftReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rs = (opCode >> 0) & 0xf;

ShiftType = (ShiftType)((opCode >> 21) & 3);
}
}
}
16 changes: 16 additions & 0 deletions ARMeilleure/Decoders/OpCodeT32Tb.cs
@@ -0,0 +1,16 @@
namespace ARMeilleure.Decoders
{
class OpCodeT32Tb : OpCodeT32, IOpCode32BReg
{
public int Rm { get; }
public int Rn { get; }

public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32Tb(inst, address, opCode);

public OpCodeT32Tb(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = (opCode >> 0) & 0xf;
Rn = (opCode >> 16) & 0xf;
}
}
}
16 changes: 13 additions & 3 deletions ARMeilleure/Decoders/OpCodeTable.cs
Expand Up @@ -1021,7 +1021,7 @@ static OpCodeTable()
SetT16("01000101xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegHigh.Create);
SetT16("01000110xxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluRegHigh.Create);
SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blx, OpCodeT16BReg.Create);
SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blxr, OpCodeT16BReg.Create);
SetT16("01001xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemLit.Create);
SetT16("0101000xxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemReg.Create);
SetT16("0101001xxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemReg.Create);
Expand Down Expand Up @@ -1069,6 +1069,7 @@ static OpCodeTable()
SetT32("11110x01010xxxxx0xxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT32AluImm.Create);
SetT32("11101011000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluRsImm.Create);
SetT32("11110x01000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluImm.Create);
SetT32("11110x100000xxxx0xxxxxxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluImm12.Create);
SetT32("11101010000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluRsImm.Create);
SetT32("11110x00000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluImm.Create);
SetT32("11110x<<<xxxxxxx10x0xxxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT32BImm20.Create);
Expand All @@ -1077,12 +1078,14 @@ static OpCodeTable()
SetT32("11110x00001xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT32AluImm.Create);
SetT32("11110xxxxxxxxxxx11x1xxxxxxxxxxxx", InstName.Bl, InstEmit32.Bl, OpCodeT32BImm24.Create);
SetT32("11110xxxxxxxxxxx11x0xxxxxxxxxxx0", InstName.Blx, InstEmit32.Blx, OpCodeT32BImm24.Create);
SetT32("111110101011xxxx1111xxxx1000xxxx", InstName.Clz, InstEmit32.Clz, OpCodeT32AluReg.Create);
SetT32("111010110001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluRsImm.Create);
SetT32("11110x010001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluImm.Create);
SetT32("111010111011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluRsImm.Create);
SetT32("11110x011011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluImm.Create);
SetT32("11101010100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluRsImm.Create);
SetT32("11110x00100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluImm.Create);
SetT32("111010001101xxxxxxxx111110101111", InstName.Lda, InstEmit32.Lda, OpCodeT32MemLdEx.Create);
SetT32("111010001101xxxxxxxx111111101111", InstName.Ldaex, InstEmit32.Ldaex, OpCodeT32MemLdEx.Create);
SetT32("1110100010x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
SetT32("1110100100x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
Expand All @@ -1095,7 +1098,8 @@ static OpCodeTable()
SetT32("111110000001xxxx<<<<1100xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
SetT32("111110000001xxxx<<<<11x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
SetT32("111110001001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm12.Create);
SetT32("1110100>x1>1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
SetT32("11101000x111<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
SetT32("11101001x1x1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
SetT32("111110000011xxxx<<<<10x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
SetT32("111110000011xxxx<<<<1100xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
SetT32("111110000011xxxx<<<<11x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
Expand All @@ -1109,9 +1113,12 @@ static OpCodeTable()
SetT32("111110010011xxxx<<<<11x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
SetT32("111110011011xxxxxxxxxxxxxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm12.Create);
SetT32("11101010010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluRsImm.Create);
SetT32("111110100xxxxxxx1111xxxx0000xxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32ShiftReg.Create);
SetT32("11110x00010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluImm.Create);
SetT32("11110x100100xxxx0xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32MovImm16.Create);
SetT32("11101010011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluRsImm.Create);
SetT32("11110x00011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluImm.Create);
SetT32("11110011101011111000000000000000", InstName.Nop, InstEmit32.Nop, OpCodeT32.Create);
SetT32("11101010011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluRsImm.Create);
SetT32("11110x00011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluImm.Create);
SetT32("11101010010x<<<<0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT32AluRsImm.Create);
Expand All @@ -1128,11 +1135,14 @@ static OpCodeTable()
SetT32("111110000100<<<<xxxx000000xxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemRsImm.Create);
SetT32("111110000000xxxxxxxx1<<>xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create);
SetT32("1110100>x1>0<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
SetT32("11101000x110<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
SetT32("11101001x1x0<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
SetT32("111110000010xxxxxxxx1<<>xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm12.Create);
SetT32("11101011101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluRsImm.Create);
SetT32("11110x01101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluImm.Create);
SetT32("111010001101xxxx111100000000xxxx", InstName.Tbb, InstEmit32.Tbb, OpCodeT32Tb.Create);
SetT32("111010001101xxxx111100000001xxxx", InstName.Tbh, InstEmit32.Tbh, OpCodeT32Tb.Create);
SetT32("111010101001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluRsImm.Create);
SetT32("11110x001001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluImm.Create);
SetT32("111010100001xxxx0xxx1111xxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT32AluRsImm.Create);
Expand Down
25 changes: 25 additions & 0 deletions ARMeilleure/Instructions/InstEmitFlow32.cs
Expand Up @@ -107,5 +107,30 @@ public static void It(ArmEmitterContext context)

context.SetIfThenBlockState(op.IfThenBlockConds);
}

public static void Tbb(ArmEmitterContext context) => EmitTb(context, halfword: false);
public static void Tbh(ArmEmitterContext context) => EmitTb(context, halfword: true);

private static void EmitTb(ArmEmitterContext context, bool halfword)
{
OpCodeT32Tb op = (OpCodeT32Tb)context.CurrOp;

Operand halfwords;

if (halfword)
{
Operand address = context.Add(GetIntA32(context, op.Rn), context.ShiftLeft(GetIntA32(context, op.Rm), Const(1)));
halfwords = InstEmitMemoryHelper.EmitReadInt(context, address, 1);
}
else
{
Operand address = context.Add(GetIntA32(context, op.Rn), GetIntA32(context, op.Rm));
halfwords = InstEmitMemoryHelper.EmitReadIntAligned(context, address, 0);
}

Operand targetAddress = context.Add(Const((int)op.GetPc()), context.ShiftLeft(halfwords, Const(1)));

EmitVirtualJump(context, targetAddress, isReturn: false);
}
}
}
16 changes: 8 additions & 8 deletions ARMeilleure/Instructions/InstEmitMemory32.cs
Expand Up @@ -204,15 +204,15 @@ void Load(int rt, int offs, int loadSize)

context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));

Load(op.Rt, 0, WordSizeLog2);
Load(op.Rt | 1, 4, WordSizeLog2);
Load(op.Rt, 0, WordSizeLog2);
Load(op.Rt2, 4, WordSizeLog2);

context.Branch(lblEnd);

context.MarkLabel(lblBigEndian);

Load(op.Rt | 1, 0, WordSizeLog2);
Load(op.Rt, 4, WordSizeLog2);
Load(op.Rt2, 0, WordSizeLog2);
Load(op.Rt, 4, WordSizeLog2);

context.MarkLabel(lblEnd);
}
Expand All @@ -237,15 +237,15 @@ void Store(int rt, int offs, int storeSize)

context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));

Store(op.Rt, 0, WordSizeLog2);
Store(op.Rt | 1, 4, WordSizeLog2);
Store(op.Rt, 0, WordSizeLog2);
Store(op.Rt2, 4, WordSizeLog2);

context.Branch(lblEnd);

context.MarkLabel(lblBigEndian);

Store(op.Rt | 1, 0, WordSizeLog2);
Store(op.Rt, 4, WordSizeLog2);
Store(op.Rt2, 0, WordSizeLog2);
Store(op.Rt, 4, WordSizeLog2);

context.MarkLabel(lblEnd);
}
Expand Down
42 changes: 41 additions & 1 deletion ARMeilleure/Instructions/InstEmitMemoryHelper.cs
Expand Up @@ -123,6 +123,41 @@ private static bool IsSimd(ArmEmitterContext context)
context.CurrOp is OpCodeSimdMemSs);
}

public static Operand EmitReadInt(ArmEmitterContext context, Operand address, int size)
{
Operand temp = context.AllocateLocal(size == 3 ? OperandType.I64 : OperandType.I32);

Operand lblSlowPath = Label();
Operand lblEnd = Label();

Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size);

Operand value = default;

switch (size)
{
case 0: value = context.Load8 (physAddr); break;
case 1: value = context.Load16(physAddr); break;
case 2: value = context.Load (OperandType.I32, physAddr); break;
case 3: value = context.Load (OperandType.I64, physAddr); break;
}

context.Copy(temp, value);

if (!context.Memory.Type.IsHostMapped())
{
context.Branch(lblEnd);

context.MarkLabel(lblSlowPath, BasicBlockFrequency.Cold);

context.Copy(temp, EmitReadIntFallback(context, address, size));

context.MarkLabel(lblEnd);
}

return temp;
}

private static void EmitReadInt(ArmEmitterContext context, Operand address, int rt, int size)
{
Operand lblSlowPath = Label();
Expand Down Expand Up @@ -419,6 +454,11 @@ public static Operand EmitHostMappedPointer(ArmEmitterContext context, Operand a
}

private static void EmitReadIntFallback(ArmEmitterContext context, Operand address, int rt, int size)
{
SetInt(context, rt, EmitReadIntFallback(context, address, size));
}

private static Operand EmitReadIntFallback(ArmEmitterContext context, Operand address, int size)
{
MethodInfo info = null;

Expand All @@ -430,7 +470,7 @@ private static void EmitReadIntFallback(ArmEmitterContext context, Operand addre
case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break;
}

SetInt(context, rt, context.Call(info, address));
return context.Call(info, address);
}

private static void EmitReadVectorFallback(
Expand Down
2 changes: 2 additions & 0 deletions ARMeilleure/Instructions/InstName.cs
Expand Up @@ -545,6 +545,8 @@ enum InstName
Strexh,
Strh,
Sxtb16,
Tbb,
Tbh,
Teq,
Trap,
Tst,
Expand Down
2 changes: 1 addition & 1 deletion ARMeilleure/Translation/PTC/Ptc.cs
Expand Up @@ -27,7 +27,7 @@ public static class Ptc
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";

private const uint InternalVersion = 3677; //! To be incremented manually for each change to the ARMeilleure project.
private const uint InternalVersion = 3683; //! To be incremented manually for each change to the ARMeilleure project.

private const string ActualDir = "0";
private const string BackupDir = "1";
Expand Down

0 comments on commit c64524a

Please sign in to comment.