diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2019-01-29 13:06:11 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-01-29 13:06:11 -0300 |
| commit | c1bdf19061ec679aa3c69eda2a41337e3e809014 (patch) | |
| tree | f3813b8df8ff8dd1fbf73fd085893b0df21850dc /ChocolArm64/Decoders | |
| parent | 8f7fcede7fa98c605925dc7b9316940960543bf1 (diff) | |
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
Diffstat (limited to 'ChocolArm64/Decoders')
| -rw-r--r-- | ChocolArm64/Decoders/Decoder.cs | 56 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/IOpCode32Alu.cs (renamed from ChocolArm64/Decoders/IOpCodeAlu32.cs) | 2 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/IOpCode32BImm.cs | 4 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/IOpCode32BReg.cs (renamed from ChocolArm64/Decoders/IOpCodeBReg32.cs) | 2 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/IOpCode32Mem.cs | 12 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/IOpCode32MemMult.cs | 13 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/IOpCodeBImm32.cs | 4 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCode32Alu.cs (renamed from ChocolArm64/Decoders/OpCodeAlu32.cs) | 4 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCode32AluImm.cs (renamed from ChocolArm64/Decoders/OpCodeAluImm32.cs) | 4 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCode32AluRsImm.cs (renamed from ChocolArm64/Decoders/OpCodeAluRsImm32.cs) | 4 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCode32BImm.cs (renamed from ChocolArm64/Decoders/OpCodeBImm32.cs) | 4 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCode32BReg.cs (renamed from ChocolArm64/Decoders/OpCodeBReg32.cs) | 4 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCode32Mem.cs | 37 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCode32MemImm.cs | 12 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCode32MemImm8.cs | 15 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCode32MemMult.cs | 57 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCodeT16AluImm8.cs (renamed from ChocolArm64/Decoders/OpCodeAluImm8T16.cs) | 4 | ||||
| -rw-r--r-- | ChocolArm64/Decoders/OpCodeT16BReg.cs (renamed from ChocolArm64/Decoders/OpCodeBRegT16.cs) | 4 |
18 files changed, 219 insertions, 23 deletions
diff --git a/ChocolArm64/Decoders/Decoder.cs b/ChocolArm64/Decoders/Decoder.cs index 6c60e1fe..2b195412 100644 --- a/ChocolArm64/Decoders/Decoder.cs +++ b/ChocolArm64/Decoders/Decoder.cs @@ -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) diff --git a/ChocolArm64/Decoders/IOpCodeAlu32.cs b/ChocolArm64/Decoders/IOpCode32Alu.cs index 9a464886..d6f6d82a 100644 --- a/ChocolArm64/Decoders/IOpCodeAlu32.cs +++ b/ChocolArm64/Decoders/IOpCode32Alu.cs @@ -1,6 +1,6 @@ namespace ChocolArm64.Decoders { - interface IOpCodeAlu32 : IOpCode32 + interface IOpCode32Alu : IOpCode32 { int Rd { get; } int Rn { get; } diff --git a/ChocolArm64/Decoders/IOpCode32BImm.cs b/ChocolArm64/Decoders/IOpCode32BImm.cs new file mode 100644 index 00000000..b69c1e36 --- /dev/null +++ b/ChocolArm64/Decoders/IOpCode32BImm.cs @@ -0,0 +1,4 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCode32BImm : IOpCode32, IOpCodeBImm { } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCodeBReg32.cs b/ChocolArm64/Decoders/IOpCode32BReg.cs index fb9d94ea..a498b02d 100644 --- a/ChocolArm64/Decoders/IOpCodeBReg32.cs +++ b/ChocolArm64/Decoders/IOpCode32BReg.cs @@ -1,6 +1,6 @@ namespace ChocolArm64.Decoders { - interface IOpCodeBReg32 : IOpCode32 + interface IOpCode32BReg : IOpCode32 { int Rm { get; } } diff --git a/ChocolArm64/Decoders/IOpCode32Mem.cs b/ChocolArm64/Decoders/IOpCode32Mem.cs new file mode 100644 index 00000000..8ed25add --- /dev/null +++ b/ChocolArm64/Decoders/IOpCode32Mem.cs @@ -0,0 +1,12 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCode32Mem : IOpCode32 + { + int Rt { get; } + int Rn { get; } + + bool WBack { get; } + + bool IsLoad { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCode32MemMult.cs b/ChocolArm64/Decoders/IOpCode32MemMult.cs new file mode 100644 index 00000000..d611c53b --- /dev/null +++ b/ChocolArm64/Decoders/IOpCode32MemMult.cs @@ -0,0 +1,13 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCode32MemMult : IOpCode32 + { + int Rn { get; } + + int RegisterMask { get; } + + int PostOffset { get; } + + bool IsLoad { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCodeBImm32.cs b/ChocolArm64/Decoders/IOpCodeBImm32.cs deleted file mode 100644 index cc8248f2..00000000 --- a/ChocolArm64/Decoders/IOpCodeBImm32.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace ChocolArm64.Decoders -{ - interface IOpCodeBImm32 : IOpCode32, IOpCodeBImm { } -}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeAlu32.cs b/ChocolArm64/Decoders/OpCode32Alu.cs index 9612d9c2..0cf06696 100644 --- a/ChocolArm64/Decoders/OpCodeAlu32.cs +++ b/ChocolArm64/Decoders/OpCode32Alu.cs @@ -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; diff --git a/ChocolArm64/Decoders/OpCodeAluImm32.cs b/ChocolArm64/Decoders/OpCode32AluImm.cs index 22436709..4302f117 100644 --- a/ChocolArm64/Decoders/OpCodeAluImm32.cs +++ b/ChocolArm64/Decoders/OpCode32AluImm.cs @@ -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; diff --git a/ChocolArm64/Decoders/OpCodeAluRsImm32.cs b/ChocolArm64/Decoders/OpCode32AluRsImm.cs index 7b860448..f23916be 100644 --- a/ChocolArm64/Decoders/OpCodeAluRsImm32.cs +++ b/ChocolArm64/Decoders/OpCode32AluRsImm.cs @@ -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; diff --git a/ChocolArm64/Decoders/OpCodeBImm32.cs b/ChocolArm64/Decoders/OpCode32BImm.cs index 127ac174..43f191eb 100644 --- a/ChocolArm64/Decoders/OpCodeBImm32.cs +++ b/ChocolArm64/Decoders/OpCode32BImm.cs @@ -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(); diff --git a/ChocolArm64/Decoders/OpCodeBReg32.cs b/ChocolArm64/Decoders/OpCode32BReg.cs index f89b1ae1..4a0fa537 100644 --- a/ChocolArm64/Decoders/OpCodeBReg32.cs +++ b/ChocolArm64/Decoders/OpCode32BReg.cs @@ -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; } diff --git a/ChocolArm64/Decoders/OpCode32Mem.cs b/ChocolArm64/Decoders/OpCode32Mem.cs new file mode 100644 index 00000000..ed648a5f --- /dev/null +++ b/ChocolArm64/Decoders/OpCode32Mem.cs @@ -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; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCode32MemImm.cs b/ChocolArm64/Decoders/OpCode32MemImm.cs new file mode 100644 index 00000000..ca46e08f --- /dev/null +++ b/ChocolArm64/Decoders/OpCode32MemImm.cs @@ -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; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCode32MemImm8.cs b/ChocolArm64/Decoders/OpCode32MemImm8.cs new file mode 100644 index 00000000..02e446e8 --- /dev/null +++ b/ChocolArm64/Decoders/OpCode32MemImm8.cs @@ -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); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCode32MemMult.cs b/ChocolArm64/Decoders/OpCode32MemMult.cs new file mode 100644 index 00000000..652da8a5 --- /dev/null +++ b/ChocolArm64/Decoders/OpCode32MemMult.cs @@ -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; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeAluImm8T16.cs b/ChocolArm64/Decoders/OpCodeT16AluImm8.cs index beb6dcaa..52c059f4 100644 --- a/ChocolArm64/Decoders/OpCodeAluImm8T16.cs +++ b/ChocolArm64/Decoders/OpCodeT16AluImm8.cs @@ -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; diff --git a/ChocolArm64/Decoders/OpCodeBRegT16.cs b/ChocolArm64/Decoders/OpCodeT16BReg.cs index c6c25130..29514700 100644 --- a/ChocolArm64/Decoders/OpCodeBRegT16.cs +++ b/ChocolArm64/Decoders/OpCodeT16BReg.cs @@ -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; } |
