diff options
Diffstat (limited to 'ChocolArm64/Instruction/AInstEmitSimdMemory.cs')
| -rw-r--r-- | ChocolArm64/Instruction/AInstEmitSimdMemory.cs | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/ChocolArm64/Instruction/AInstEmitSimdMemory.cs b/ChocolArm64/Instruction/AInstEmitSimdMemory.cs new file mode 100644 index 00000000..d98ec012 --- /dev/null +++ b/ChocolArm64/Instruction/AInstEmitSimdMemory.cs @@ -0,0 +1,184 @@ +using ChocolArm64.Decoder; +using ChocolArm64.State; +using ChocolArm64.Translation; +using System; +using System.Reflection.Emit; + +using static ChocolArm64.Instruction.AInstEmitMemoryHelper; +using static ChocolArm64.Instruction.AInstEmitSimdHelper; + +namespace ChocolArm64.Instruction +{ + static partial class AInstEmit + { + public static void Ld__Vms(AILEmitterCtx Context) + { + EmitSimdMemMs(Context, IsLoad: true); + } + + public static void Ld__Vss(AILEmitterCtx Context) + { + EmitSimdMemSs(Context, IsLoad: true); + } + + public static void St__Vms(AILEmitterCtx Context) + { + EmitSimdMemMs(Context, IsLoad: false); + } + + public static void St__Vss(AILEmitterCtx Context) + { + EmitSimdMemSs(Context, IsLoad: false); + } + + private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad) + { + AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp; + + int Offset = 0; + + for (int Rep = 0; Rep < Op.Reps; Rep++) + for (int Elem = 0; Elem < Op.Elems; Elem++) + for (int SElem = 0; SElem < Op.SElems; SElem++) + { + int Rtt = (Op.Rt + Rep + SElem) & 0x1f; + + if (IsLoad) + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I8(Offset); + + Context.Emit(OpCodes.Add); + + EmitReadZxCall(Context, Op.Size); + + EmitVectorInsert(Context, Rtt, Elem, Op.Size); + + if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1) + { + EmitVectorZeroUpper(Context, Rtt); + } + } + else + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I8(Offset); + + Context.Emit(OpCodes.Add); + + EmitVectorExtractZx(Context, Rtt, Elem, Op.Size); + + EmitWriteCall(Context, Op.Size); + } + + Offset += 1 << Op.Size; + } + + if (Op.WBack) + { + EmitSimdMemWBack(Context, Offset); + } + } + + private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad) + { + AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp; + + int Offset = 0; + + void EmitMemAddress() + { + Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); + Context.EmitLdint(Op.Rn); + Context.EmitLdc_I8(Offset); + + Context.Emit(OpCodes.Add); + } + + if (Op.Replicate) + { + //Only loads uses the replicate mode. + if (!IsLoad) + { + throw new InvalidOperationException(); + } + + int Bytes = Context.CurrOp.GetBitsCount() >> 3; + + for (int SElem = 0; SElem < Op.SElems; SElem++) + { + int Rt = (Op.Rt + SElem) & 0x1f; + + for (int Index = 0; Index < (Bytes >> Op.Size); Index++) + { + EmitMemAddress(); + + EmitReadZxCall(Context, Op.Size); + + EmitVectorInsert(Context, Rt, Index, Op.Size); + } + + if (Op.RegisterSize == ARegisterSize.SIMD64) + { + EmitVectorZeroUpper(Context, Rt); + } + + Offset += 1 << Op.Size; + } + } + else + { + for (int SElem = 0; SElem < Op.SElems; SElem++) + { + int Rt = (Op.Rt + SElem) & 0x1f; + + if (IsLoad) + { + EmitMemAddress(); + + EmitReadZxCall(Context, Op.Size); + + EmitVectorInsert(Context, Rt, Op.Index, Op.Size); + } + else + { + EmitMemAddress(); + + EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size); + + EmitWriteCall(Context, Op.Size); + } + + Offset += 1 << Op.Size; + } + } + + if (Op.WBack) + { + EmitSimdMemWBack(Context, Offset); + } + } + + private static void EmitSimdMemWBack(AILEmitterCtx Context, int Offset) + { + AOpCodeMemReg Op = (AOpCodeMemReg)Context.CurrOp; + + Context.EmitLdint(Op.Rn); + + if (Op.Rm != AThreadState.ZRIndex) + { + Context.EmitLdint(Op.Rm); + } + else + { + Context.EmitLdc_I8(Offset); + } + + Context.Emit(OpCodes.Add); + + Context.EmitStint(Op.Rn); + } + } +}
\ No newline at end of file |
