using ChocolArm64.Decoders; using ChocolArm64.State; using ChocolArm64.Translation; using System; using System.Reflection.Emit; using static ChocolArm64.Instructions.InstEmitMemoryHelper; using static ChocolArm64.Instructions.InstEmitSimdHelper; namespace ChocolArm64.Instructions { static partial class InstEmit { public static void Ld__Vms(ILEmitterCtx context) { EmitSimdMemMs(context, isLoad: true); } public static void Ld__Vss(ILEmitterCtx context) { EmitSimdMemSs(context, isLoad: true); } public static void St__Vms(ILEmitterCtx context) { EmitSimdMemMs(context, isLoad: false); } public static void St__Vss(ILEmitterCtx context) { EmitSimdMemSs(context, isLoad: false); } private static void EmitSimdMemMs(ILEmitterCtx context, bool isLoad) { OpCodeSimdMemMs64 op = (OpCodeSimdMemMs64)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.EmitLdint(op.Rn); context.EmitLdc_I8(offset); context.Emit(OpCodes.Add); EmitReadZxCall(context, op.Size); EmitVectorInsert(context, rtt, elem, op.Size); if (op.RegisterSize == RegisterSize.Simd64 && elem == op.Elems - 1) { EmitVectorZeroUpper(context, rtt); } } else { 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(ILEmitterCtx context, bool isLoad) { OpCodeSimdMemSs64 op = (OpCodeSimdMemSs64)context.CurrOp; int offset = 0; void EmitMemAddress() { 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 = op.GetBitsCount() >> 3; int elems = bytes >> op.Size; for (int sElem = 0; sElem < op.SElems; sElem++) { int rt = (op.Rt + sElem) & 0x1f; for (int index = 0; index < elems; index++) { EmitMemAddress(); EmitReadZxCall(context, op.Size); EmitVectorInsert(context, rt, index, op.Size); } if (op.RegisterSize == RegisterSize.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(ILEmitterCtx context, int offset) { OpCodeMemReg64 op = (OpCodeMemReg64)context.CurrOp; context.EmitLdint(op.Rn); if (op.Rm != RegisterAlias.Zr) { context.EmitLdint(op.Rm); } else { context.EmitLdc_I8(offset); } context.Emit(OpCodes.Add); context.EmitStint(op.Rn); } } }