diff options
Diffstat (limited to 'ChocolArm64/Instruction/AInstEmitMemory.cs')
| -rw-r--r-- | ChocolArm64/Instruction/AInstEmitMemory.cs | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/ChocolArm64/Instruction/AInstEmitMemory.cs b/ChocolArm64/Instruction/AInstEmitMemory.cs new file mode 100644 index 00000000..af7de3ba --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitMemory.cs @@ -0,0 +1,252 @@ +using ChocolArm64.Decoder; +using ChocolArm64.Translation; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitMemoryHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Adr(AILEmitterCtx Context) + { + AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp; + + Context.EmitLdc_I(Op.Position + Op.Imm); + Context.EmitStintzr(Op.Rd); + } + + public static void Adrp(AILEmitterCtx Context) + { + AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp; + + Context.EmitLdc_I((Op.Position & ~0xfffL) + (Op.Imm << 12)); + Context.EmitStintzr(Op.Rd); + } + + public static void Ldr(AILEmitterCtx Context) => EmitLdr(Context, false); + public static void Ldrs(AILEmitterCtx Context) => EmitLdr(Context, true); + + public static void EmitLdr(AILEmitterCtx Context, bool Signed) + { + AOpCodeMem Op = (AOpCodeMem)Context.CurrOp; + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + + EmitLoadAddress(Context); + + if (Signed && Op.Extend64) + { + EmitReadSx64Call(Context, Op.Size); + } + else if (Signed) + { + EmitReadSx32Call(Context, Op.Size); + } + else + { + EmitReadZxCall(Context, Op.Size); + } + + if (Op is IAOpCodeSimd) + { + Context.EmitStvec(Op.Rt); + } + else + { + Context.EmitStintzr(Op.Rt); + } + + EmitWBackIfNeeded(Context); + } + + public static void LdrLit(AILEmitterCtx Context) + { + IAOpCodeLit Op = (IAOpCodeLit)Context.CurrOp; + + if (Op.Prefetch) + { + return; + } + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdc_I8(Op.Imm); + + if (Op.Signed) + { + EmitReadSx64Call(Context, Op.Size); + } + else + { + EmitReadZxCall(Context, Op.Size); + } + + if (Op is IAOpCodeSimd) + { + Context.EmitStvec(Op.Rt); + } + else + { + Context.EmitStint(Op.Rt); + } + } + + public static void Ldp(AILEmitterCtx Context) + { + AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp; + + void EmitReadAndStore(int Rt) + { + if (Op.Extend64) + { + EmitReadSx64Call(Context, Op.Size); + } + else + { + EmitReadZxCall(Context, Op.Size); + } + + if (Op is IAOpCodeSimd) + { + Context.EmitStvec(Rt); + } + else + { + Context.EmitStintzr(Rt); + } + } + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + + EmitLoadAddress(Context); + + EmitReadAndStore(Op.Rt); + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdtmp(); + Context.EmitLdc_I8(1 << Op.Size); + + Context.Emit(OpCodes.Add); + + EmitReadAndStore(Op.Rt2); + + EmitWBackIfNeeded(Context); + } + + public static void Str(AILEmitterCtx Context) + { + AOpCodeMem Op = (AOpCodeMem)Context.CurrOp; + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + + EmitLoadAddress(Context); + + if (Op is IAOpCodeSimd) + { + Context.EmitLdvec(Op.Rt); + } + else + { + Context.EmitLdintzr(Op.Rt); + } + + EmitWriteCall(Context, Op.Size); + + EmitWBackIfNeeded(Context); + } + + public static void Stp(AILEmitterCtx Context) + { + AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp; + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + + EmitLoadAddress(Context); + + if (Op is IAOpCodeSimd) + { + Context.EmitLdvec(Op.Rt); + } + else + { + Context.EmitLdintzr(Op.Rt); + } + + EmitWriteCall(Context, Op.Size); + + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdtmp(); + Context.EmitLdc_I8(1 << Op.Size); + + Context.Emit(OpCodes.Add); + + if (Op is IAOpCodeSimd) + { + Context.EmitLdvec(Op.Rt2); + } + else + { + Context.EmitLdintzr(Op.Rt2); + } + + EmitWriteCall(Context, Op.Size); + + EmitWBackIfNeeded(Context); + } + + private static void EmitLoadAddress(AILEmitterCtx Context) + { + switch (Context.CurrOp) + { + case AOpCodeMemImm Op: + Context.EmitLdint(Op.Rn); + + if (!Op.PostIdx) + { + //Pre-indexing. + Context.EmitLdc_I(Op.Imm); + + Context.Emit(OpCodes.Add); + } + break; + + case AOpCodeMemReg Op: + Context.EmitLdint(Op.Rn); + Context.EmitLdintzr(Op.Rm); + Context.EmitCast(Op.IntType); + + if (Op.Shift) + { + Context.EmitLsl(Op.Size); + } + + Context.Emit(OpCodes.Add); + break; + } + + //Save address to Scratch var since the register value may change. + Context.Emit(OpCodes.Dup); + + Context.EmitSttmp(); + } + + private static void EmitWBackIfNeeded(AILEmitterCtx Context) + { + //Check whenever the current OpCode has post-indexed write back, if so write it. + //Note: AOpCodeMemPair inherits from AOpCodeMemImm, so this works for both. + if (Context.CurrOp is AOpCodeMemImm Op && Op.WBack) + { + Context.EmitLdtmp(); + + if (Op.PostIdx) + { + Context.EmitLdc_I(Op.Imm); + + Context.Emit(OpCodes.Add); + } + + Context.EmitStint(Op.Rn); + } + } + } +}
\ No newline at end of file |
