| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- using ChocolArm64.Decoders;
- using ChocolArm64.IntermediateRepresentation;
- using ChocolArm64.State;
- using ChocolArm64.Translation;
- using System;
- using System.Reflection.Emit;
- using static ChocolArm64.Instructions.InstEmit32Helper;
- using static ChocolArm64.Instructions.InstEmitMemoryHelper;
- namespace ChocolArm64.Instructions
- {
- static partial class InstEmit32
- {
- private const int ByteSizeLog2 = 0;
- private const int HWordSizeLog2 = 1;
- private const int WordSizeLog2 = 2;
- private const int DWordSizeLog2 = 3;
- [Flags]
- enum AccessType
- {
- Store = 0,
- Signed = 1,
- Load = 2,
- LoadZx = Load,
- LoadSx = Load | Signed,
- }
- public static void Ldm(ILEmitterCtx context)
- {
- OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
- EmitLoadFromRegister(context, op.Rn);
- bool writesToPc = (op.RegisterMask & (1 << RegisterAlias.Aarch32Pc)) != 0;
- bool writeBack = op.PostOffset != 0 && (op.Rn != RegisterAlias.Aarch32Pc || !writesToPc);
- if (writeBack)
- {
- context.Emit(OpCodes.Dup);
- }
- context.EmitLdc_I4(op.Offset);
- context.Emit(OpCodes.Add);
- context.EmitSttmp();
- if (writeBack)
- {
- context.EmitLdc_I4(op.PostOffset);
- context.Emit(OpCodes.Add);
- EmitStoreToRegister(context, op.Rn);
- }
- int mask = op.RegisterMask;
- int offset = 0;
- for (int register = 0; mask != 0; mask >>= 1, register++)
- {
- if ((mask & 1) != 0)
- {
- context.EmitLdtmp();
- context.EmitLdc_I4(offset);
- context.Emit(OpCodes.Add);
- EmitReadZxCall(context, WordSizeLog2);
- EmitStoreToRegister(context, register);
- offset += 4;
- }
- }
- }
- public static void Ldr(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, WordSizeLog2, AccessType.LoadZx);
- }
- public static void Ldrb(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx);
- }
- public static void Ldrd(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx);
- }
- public static void Ldrh(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx);
- }
- public static void Ldrsb(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadSx);
- }
- public static void Ldrsh(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadSx);
- }
- public static void Stm(ILEmitterCtx context)
- {
- OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
- EmitLoadFromRegister(context, op.Rn);
- context.EmitLdc_I4(op.Offset);
- context.Emit(OpCodes.Add);
- context.EmitSttmp();
- int mask = op.RegisterMask;
- int offset = 0;
- for (int register = 0; mask != 0; mask >>= 1, register++)
- {
- if ((mask & 1) != 0)
- {
- context.EmitLdtmp();
- context.EmitLdc_I4(offset);
- context.Emit(OpCodes.Add);
- EmitLoadFromRegister(context, register);
- EmitWriteCall(context, WordSizeLog2);
- // Note: If Rn is also specified on the register list,
- // and Rn is the first register on this list, then the
- // value that is written to memory is the unmodified value,
- // before the write back. If it is on the list, but it's
- // not the first one, then the value written to memory
- // varies between CPUs.
- if (offset == 0 && op.PostOffset != 0)
- {
- // Emit write back after the first write.
- EmitLoadFromRegister(context, op.Rn);
- context.EmitLdc_I4(op.PostOffset);
- context.Emit(OpCodes.Add);
- EmitStoreToRegister(context, op.Rn);
- }
- offset += 4;
- }
- }
- }
- public static void Str(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, WordSizeLog2, AccessType.Store);
- }
- public static void Strb(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, ByteSizeLog2, AccessType.Store);
- }
- public static void Strd(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, DWordSizeLog2, AccessType.Store);
- }
- public static void Strh(ILEmitterCtx context)
- {
- EmitLoadOrStore(context, HWordSizeLog2, AccessType.Store);
- }
- private static void EmitLoadOrStore(ILEmitterCtx context, int size, AccessType accType)
- {
- OpCode32Mem op = (OpCode32Mem)context.CurrOp;
- if (op.Index || op.WBack)
- {
- EmitLoadFromRegister(context, op.Rn);
- context.EmitLdc_I4(op.Imm);
- context.Emit(op.Add ? OpCodes.Add : OpCodes.Sub);
- context.EmitSttmp();
- }
- if (op.Index)
- {
- context.EmitLdtmp();
- }
- else
- {
- EmitLoadFromRegister(context, op.Rn);
- }
- if ((accType & AccessType.Load) != 0)
- {
- if ((accType & AccessType.Signed) != 0)
- {
- EmitReadSx32Call(context, size);
- }
- else
- {
- EmitReadZxCall(context, size);
- }
- if (op.WBack)
- {
- context.EmitLdtmp();
- EmitStoreToRegister(context, op.Rn);
- }
- if (size == DWordSizeLog2)
- {
- context.Emit(OpCodes.Dup);
- context.EmitLdflg((int)PState.EBit);
- ILLabel lblBigEndian = new ILLabel();
- ILLabel lblEnd = new ILLabel();
- context.Emit(OpCodes.Brtrue_S, lblBigEndian);
- // Little endian mode.
- context.Emit(OpCodes.Conv_U4);
- EmitStoreToRegister(context, op.Rt);
- context.EmitLsr(32);
- context.Emit(OpCodes.Conv_U4);
- EmitStoreToRegister(context, op.Rt | 1);
- context.Emit(OpCodes.Br_S, lblEnd);
- // Big endian mode.
- context.MarkLabel(lblBigEndian);
- context.EmitLsr(32);
- context.Emit(OpCodes.Conv_U4);
- EmitStoreToRegister(context, op.Rt);
- context.Emit(OpCodes.Conv_U4);
- EmitStoreToRegister(context, op.Rt | 1);
- context.MarkLabel(lblEnd);
- }
- else
- {
- EmitStoreToRegister(context, op.Rt);
- }
- }
- else
- {
- if (op.WBack)
- {
- context.EmitLdtmp();
- EmitStoreToRegister(context, op.Rn);
- }
- EmitLoadFromRegister(context, op.Rt);
- if (size == DWordSizeLog2)
- {
- context.Emit(OpCodes.Conv_U8);
- context.EmitLdflg((int)PState.EBit);
- ILLabel lblBigEndian = new ILLabel();
- ILLabel lblEnd = new ILLabel();
- context.Emit(OpCodes.Brtrue_S, lblBigEndian);
- // Little endian mode.
- EmitLoadFromRegister(context, op.Rt | 1);
- context.Emit(OpCodes.Conv_U8);
- context.EmitLsl(32);
- context.Emit(OpCodes.Or);
- context.Emit(OpCodes.Br_S, lblEnd);
- // Big endian mode.
- context.MarkLabel(lblBigEndian);
- context.EmitLsl(32);
- EmitLoadFromRegister(context, op.Rt | 1);
- context.Emit(OpCodes.Conv_U8);
- context.Emit(OpCodes.Or);
- context.MarkLabel(lblEnd);
- }
- EmitWriteCall(context, size);
- }
- }
- }
- }
|