Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ADD (zx imm12), NOP, MOV (rs), LDA, TBB, TBH, MOV (zx imm16) and CLZ thumb instructions #3683

Merged
merged 2 commits into from Sep 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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