Implement some ARM32 memory instructions and CMP (#565)
* Implement ARM32 memory instructions: LDM, LDR, LDRB, LDRD, LDRH, LDRSB, LDRSH, STM, STR, STRB, STRD, STRH (immediate and register + immediate variants), implement CMP (immediate and register shifted by immediate variants) * Rename some opcode classes and flag masks for consistency * Fix a few suboptimal ARM32 codegen issues, only loads should be considered on decoder when checking if Rt == PC, and only NZCV flags should be considered for comparison optimizations * Take into account Rt2 for LDRD instructions aswell when checking if the instruction changes PC * Re-align arm32 instructions on the opcode table
This commit is contained in:
parent
8f7fcede7f
commit
c1bdf19061
29 changed files with 686 additions and 87 deletions
|
@ -168,9 +168,59 @@ namespace ChocolArm64.Decoders
|
|||
{
|
||||
//Note: On ARM32, most ALU operations can write to R15 (PC),
|
||||
//so we must consider such operations as a branch in potential aswell.
|
||||
return opCode is IOpCodeBImm32 ||
|
||||
opCode is IOpCodeBReg32 ||
|
||||
(opCode is IOpCodeAlu32 op && op.Rd == RegisterAlias.Aarch32Pc);
|
||||
if (opCode is IOpCode32Alu opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//Same thing for memory operations. We have the cases where PC is a target
|
||||
//register (Rt == 15 or (mask & (1 << 15)) != 0), and cases where there is
|
||||
//a write back to PC (wback == true && Rn == 15), however the later may
|
||||
//be "undefined" depending on the CPU, so compilers should not produce that.
|
||||
if (opCode is IOpCode32Mem || opCode is IOpCode32MemMult)
|
||||
{
|
||||
int rt, rn;
|
||||
|
||||
bool wBack, isLoad;
|
||||
|
||||
if (opCode is IOpCode32Mem opMem)
|
||||
{
|
||||
rt = opMem.Rt;
|
||||
rn = opMem.Rn;
|
||||
wBack = opMem.WBack;
|
||||
isLoad = opMem.IsLoad;
|
||||
|
||||
//For the dual load, we also need to take into account the
|
||||
//case were Rt2 == 15 (PC).
|
||||
if (rt == 14 && opMem.Emitter == InstEmit32.Ldrd)
|
||||
{
|
||||
rt = RegisterAlias.Aarch32Pc;
|
||||
}
|
||||
}
|
||||
else if (opCode is IOpCode32MemMult opMemMult)
|
||||
{
|
||||
const int pcMask = 1 << RegisterAlias.Aarch32Pc;
|
||||
|
||||
rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
|
||||
rn = opMemMult.Rn;
|
||||
wBack = opMemMult.PostOffset != 0;
|
||||
isLoad = opMemMult.IsLoad;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"The type \"{opCode.GetType().Name}\" is not implemented on the decoder.");
|
||||
}
|
||||
|
||||
if ((rt == RegisterAlias.Aarch32Pc && isLoad) ||
|
||||
(rn == RegisterAlias.Aarch32Pc && wBack))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Explicit branch instructions.
|
||||
return opCode is IOpCode32BImm ||
|
||||
opCode is IOpCode32BReg;
|
||||
}
|
||||
|
||||
private static bool IsException(OpCode64 opCode)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
interface IOpCodeAlu32 : IOpCode32
|
||||
interface IOpCode32Alu : IOpCode32
|
||||
{
|
||||
int Rd { get; }
|
||||
int Rn { get; }
|
4
ChocolArm64/Decoders/IOpCode32BImm.cs
Normal file
4
ChocolArm64/Decoders/IOpCode32BImm.cs
Normal file
|
@ -0,0 +1,4 @@
|
|||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
interface IOpCode32BImm : IOpCode32, IOpCodeBImm { }
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
interface IOpCodeBReg32 : IOpCode32
|
||||
interface IOpCode32BReg : IOpCode32
|
||||
{
|
||||
int Rm { get; }
|
||||
}
|
12
ChocolArm64/Decoders/IOpCode32Mem.cs
Normal file
12
ChocolArm64/Decoders/IOpCode32Mem.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
interface IOpCode32Mem : IOpCode32
|
||||
{
|
||||
int Rt { get; }
|
||||
int Rn { get; }
|
||||
|
||||
bool WBack { get; }
|
||||
|
||||
bool IsLoad { get; }
|
||||
}
|
||||
}
|
13
ChocolArm64/Decoders/IOpCode32MemMult.cs
Normal file
13
ChocolArm64/Decoders/IOpCode32MemMult.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
interface IOpCode32MemMult : IOpCode32
|
||||
{
|
||||
int Rn { get; }
|
||||
|
||||
int RegisterMask { get; }
|
||||
|
||||
int PostOffset { get; }
|
||||
|
||||
bool IsLoad { get; }
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
interface IOpCodeBImm32 : IOpCode32, IOpCodeBImm { }
|
||||
}
|
|
@ -2,14 +2,14 @@ using ChocolArm64.Instructions;
|
|||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCodeAlu32 : OpCode32, IOpCodeAlu32
|
||||
class OpCode32Alu : OpCode32, IOpCode32Alu
|
||||
{
|
||||
public int Rd { get; private set; }
|
||||
public int Rn { get; private set; }
|
||||
|
||||
public bool SetFlags { get; private set; }
|
||||
|
||||
public OpCodeAlu32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
public OpCode32Alu(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rd = (opCode >> 12) & 0xf;
|
||||
Rn = (opCode >> 16) & 0xf;
|
|
@ -2,13 +2,13 @@ using ChocolArm64.Instructions;
|
|||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCodeAluImm32 : OpCodeAlu32
|
||||
class OpCode32AluImm : OpCode32Alu
|
||||
{
|
||||
public int Imm { get; private set; }
|
||||
|
||||
public bool IsRotated { get; private set; }
|
||||
|
||||
public OpCodeAluImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
public OpCode32AluImm(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int value = (opCode >> 0) & 0xff;
|
||||
int shift = (opCode >> 8) & 0xf;
|
|
@ -2,14 +2,14 @@ using ChocolArm64.Instructions;
|
|||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCodeAluRsImm32 : OpCodeAlu32
|
||||
class OpCode32AluRsImm : OpCode32Alu
|
||||
{
|
||||
public int Rm { get; private set; }
|
||||
public int Imm { get; private set; }
|
||||
|
||||
public ShiftType ShiftType { get; private set; }
|
||||
|
||||
public OpCodeAluRsImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
public OpCode32AluRsImm(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rm = (opCode >> 0) & 0xf;
|
||||
Imm = (opCode >> 7) & 0x1f;
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instructions;
|
|||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCodeBImm32 : OpCode32, IOpCodeBImm32
|
||||
class OpCode32BImm : OpCode32, IOpCode32BImm
|
||||
{
|
||||
public long Imm { get; private set; }
|
||||
|
||||
public OpCodeBImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
public OpCode32BImm(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
uint pc = GetPc();
|
||||
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instructions;
|
|||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCodeBReg32 : OpCode32, IOpCodeBReg32
|
||||
class OpCode32BReg : OpCode32, IOpCode32BReg
|
||||
{
|
||||
public int Rm { get; private set; }
|
||||
|
||||
public OpCodeBReg32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
public OpCode32BReg(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rm = opCode & 0xf;
|
||||
}
|
37
ChocolArm64/Decoders/OpCode32Mem.cs
Normal file
37
ChocolArm64/Decoders/OpCode32Mem.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using ChocolArm64.Instructions;
|
||||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCode32Mem : OpCode32, IOpCode32Mem
|
||||
{
|
||||
public int Rt { get; private set; }
|
||||
public int Rn { get; private set; }
|
||||
|
||||
public int Imm { get; protected set; }
|
||||
|
||||
public bool Index { get; private set; }
|
||||
public bool Add { get; private set; }
|
||||
public bool WBack { get; private set; }
|
||||
public bool Unprivileged { get; private set; }
|
||||
|
||||
public bool IsLoad { get; private set; }
|
||||
|
||||
public OpCode32Mem(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rt = (opCode >> 12) & 0xf;
|
||||
Rn = (opCode >> 16) & 0xf;
|
||||
|
||||
bool isLoad = (opCode & (1 << 20)) != 0;
|
||||
bool w = (opCode & (1 << 21)) != 0;
|
||||
bool u = (opCode & (1 << 23)) != 0;
|
||||
bool p = (opCode & (1 << 24)) != 0;
|
||||
|
||||
Index = p;
|
||||
Add = u;
|
||||
WBack = !p || w;
|
||||
Unprivileged = !p && w;
|
||||
|
||||
IsLoad = isLoad || inst.Emitter == InstEmit32.Ldrd;
|
||||
}
|
||||
}
|
||||
}
|
12
ChocolArm64/Decoders/OpCode32MemImm.cs
Normal file
12
ChocolArm64/Decoders/OpCode32MemImm.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using ChocolArm64.Instructions;
|
||||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCode32MemImm : OpCode32Mem
|
||||
{
|
||||
public OpCode32MemImm(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Imm = opCode & 0xfff;
|
||||
}
|
||||
}
|
||||
}
|
15
ChocolArm64/Decoders/OpCode32MemImm8.cs
Normal file
15
ChocolArm64/Decoders/OpCode32MemImm8.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using ChocolArm64.Instructions;
|
||||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCode32MemImm8 : OpCode32Mem
|
||||
{
|
||||
public OpCode32MemImm8(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int imm4L = (opCode >> 0) & 0xf;
|
||||
int imm4H = (opCode >> 8) & 0xf;
|
||||
|
||||
Imm = imm4L | (imm4H << 4);
|
||||
}
|
||||
}
|
||||
}
|
57
ChocolArm64/Decoders/OpCode32MemMult.cs
Normal file
57
ChocolArm64/Decoders/OpCode32MemMult.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
using ChocolArm64.Instructions;
|
||||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCode32MemMult : OpCode32, IOpCode32MemMult
|
||||
{
|
||||
public int Rn { get; private set; }
|
||||
|
||||
public int RegisterMask { get; private set; }
|
||||
public int Offset { get; private set; }
|
||||
public int PostOffset { get; private set; }
|
||||
|
||||
public bool IsLoad { get; private set; }
|
||||
|
||||
public OpCode32MemMult(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rn = (opCode >> 16) & 0xf;
|
||||
|
||||
bool isLoad = (opCode & (1 << 20)) != 0;
|
||||
bool w = (opCode & (1 << 21)) != 0;
|
||||
bool u = (opCode & (1 << 23)) != 0;
|
||||
bool p = (opCode & (1 << 24)) != 0;
|
||||
|
||||
RegisterMask = opCode & 0xffff;
|
||||
|
||||
int regsSize = 0;
|
||||
|
||||
for (int index = 0; index < 16; index++)
|
||||
{
|
||||
regsSize += (RegisterMask >> index) & 1;
|
||||
}
|
||||
|
||||
regsSize *= 4;
|
||||
|
||||
if (!u)
|
||||
{
|
||||
Offset -= regsSize;
|
||||
}
|
||||
|
||||
if (u == p)
|
||||
{
|
||||
Offset += 4;
|
||||
}
|
||||
|
||||
if (w)
|
||||
{
|
||||
PostOffset = u ? regsSize : -regsSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
PostOffset = 0;
|
||||
}
|
||||
|
||||
IsLoad = isLoad;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Instructions;
|
|||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCodeAluImm8T16 : OpCodeT16, IOpCodeAlu32
|
||||
class OpCodeT16AluImm8 : OpCodeT16, IOpCode32Alu
|
||||
{
|
||||
private int _rdn;
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace ChocolArm64.Decoders
|
|||
|
||||
public int Imm { get; private set; }
|
||||
|
||||
public OpCodeAluImm8T16(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
public OpCodeT16AluImm8(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Imm = (opCode >> 0) & 0xff;
|
||||
_rdn = (opCode >> 8) & 0x7;
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instructions;
|
|||
|
||||
namespace ChocolArm64.Decoders
|
||||
{
|
||||
class OpCodeBRegT16 : OpCodeT16, IOpCodeBReg32
|
||||
class OpCodeT16BReg : OpCodeT16, IOpCode32BReg
|
||||
{
|
||||
public int Rm { get; private set; }
|
||||
|
||||
public OpCodeBRegT16(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
public OpCodeT16BReg(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rm = (opCode >> 3) & 0xf;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue