aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Decoders/Decoder.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2019-01-29 13:06:11 -0300
committerGitHub <noreply@github.com>2019-01-29 13:06:11 -0300
commitc1bdf19061ec679aa3c69eda2a41337e3e809014 (patch)
treef3813b8df8ff8dd1fbf73fd085893b0df21850dc /ChocolArm64/Decoders/Decoder.cs
parent8f7fcede7fa98c605925dc7b9316940960543bf1 (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.cs56
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)