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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue