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/Decoder.cs | |
| 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/Decoder.cs')
| -rw-r--r-- | ChocolArm64/Decoders/Decoder.cs | 56 |
1 files changed, 53 insertions, 3 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) |
