1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
using ChocolArm64.Decoders;
using ChocolArm64.State;
using ChocolArm64.Translation;
using System;
using System.Reflection.Emit;
namespace ChocolArm64.Instructions
{
static class InstEmit32Helper
{
public static bool IsThumb(OpCode64 op)
{
return op is OpCodeT16;
}
public static void EmitLoadFromRegister(ILEmitterCtx context, int register)
{
if (register == RegisterAlias.Aarch32Pc)
{
OpCode32 op = (OpCode32)context.CurrOp;
context.EmitLdc_I4((int)op.GetPc());
}
else
{
context.EmitLdint(InstEmit32Helper.GetRegisterAlias(context.Mode, register));
}
}
public static void EmitStoreToRegister(ILEmitterCtx context, int register)
{
if (register == RegisterAlias.Aarch32Pc)
{
context.EmitStoreState();
EmitBxWritePc(context);
}
else
{
context.EmitStint(GetRegisterAlias(context.Mode, register));
}
}
public static void EmitBxWritePc(ILEmitterCtx context)
{
context.Emit(OpCodes.Dup);
context.EmitLdc_I4(1);
context.Emit(OpCodes.And);
context.Emit(OpCodes.Dup);
context.EmitStflg((int)PState.TBit);
ILLabel lblArmMode = new ILLabel();
ILLabel lblEnd = new ILLabel();
context.Emit(OpCodes.Brtrue_S, lblArmMode);
context.EmitLdc_I4(~1);
context.Emit(OpCodes.Br_S, lblEnd);
context.MarkLabel(lblArmMode);
context.EmitLdc_I4(~3);
context.MarkLabel(lblEnd);
context.Emit(OpCodes.And);
context.Emit(OpCodes.Conv_U8);
context.Emit(OpCodes.Ret);
}
public static int GetRegisterAlias(Aarch32Mode mode, int register)
{
//Only registers >= 8 are banked, with registers in the range [8, 12] being
//banked for the FIQ mode, and registers 13 and 14 being banked for all modes.
if ((uint)register < 8)
{
return register;
}
return GetBankedRegisterAlias(mode, register);
}
public static int GetBankedRegisterAlias(Aarch32Mode mode, int register)
{
switch (register)
{
case 8: return mode == Aarch32Mode.Fiq
? RegisterAlias.R8Fiq
: RegisterAlias.R8Usr;
case 9: return mode == Aarch32Mode.Fiq
? RegisterAlias.R9Fiq
: RegisterAlias.R9Usr;
case 10: return mode == Aarch32Mode.Fiq
? RegisterAlias.R10Fiq
: RegisterAlias.R10Usr;
case 11: return mode == Aarch32Mode.Fiq
? RegisterAlias.R11Fiq
: RegisterAlias.R11Usr;
case 12: return mode == Aarch32Mode.Fiq
? RegisterAlias.R12Fiq
: RegisterAlias.R12Usr;
case 13:
switch (mode)
{
case Aarch32Mode.User:
case Aarch32Mode.System: return RegisterAlias.SpUsr;
case Aarch32Mode.Fiq: return RegisterAlias.SpFiq;
case Aarch32Mode.Irq: return RegisterAlias.SpIrq;
case Aarch32Mode.Supervisor: return RegisterAlias.SpSvc;
case Aarch32Mode.Abort: return RegisterAlias.SpAbt;
case Aarch32Mode.Hypervisor: return RegisterAlias.SpHyp;
case Aarch32Mode.Undefined: return RegisterAlias.SpUnd;
default: throw new ArgumentException(nameof(mode));
}
case 14:
switch (mode)
{
case Aarch32Mode.User:
case Aarch32Mode.Hypervisor:
case Aarch32Mode.System: return RegisterAlias.LrUsr;
case Aarch32Mode.Fiq: return RegisterAlias.LrFiq;
case Aarch32Mode.Irq: return RegisterAlias.LrIrq;
case Aarch32Mode.Supervisor: return RegisterAlias.LrSvc;
case Aarch32Mode.Abort: return RegisterAlias.LrAbt;
case Aarch32Mode.Undefined: return RegisterAlias.LrUnd;
default: throw new ArgumentException(nameof(mode));
}
default: throw new ArgumentOutOfRangeException(nameof(register));
}
}
}
}
|