src/arm/arm.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/arm/arm.h>
7
8#include <mgba/internal/arm/isa-arm.h>
9#include <mgba/internal/arm/isa-inlines.h>
10#include <mgba/internal/arm/isa-thumb.h>
11
12static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode);
13
14void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
15 if (mode == cpu->privilegeMode) {
16 // Not switching modes after all
17 return;
18 }
19
20 enum RegisterBank newBank = _ARMSelectBank(mode);
21 enum RegisterBank oldBank = _ARMSelectBank(cpu->privilegeMode);
22 if (newBank != oldBank) {
23 // Switch banked registers
24 if (mode == MODE_FIQ || cpu->privilegeMode == MODE_FIQ) {
25 int oldFIQBank = oldBank == BANK_FIQ;
26 int newFIQBank = newBank == BANK_FIQ;
27 cpu->bankedRegisters[oldFIQBank][2] = cpu->gprs[8];
28 cpu->bankedRegisters[oldFIQBank][3] = cpu->gprs[9];
29 cpu->bankedRegisters[oldFIQBank][4] = cpu->gprs[10];
30 cpu->bankedRegisters[oldFIQBank][5] = cpu->gprs[11];
31 cpu->bankedRegisters[oldFIQBank][6] = cpu->gprs[12];
32 cpu->gprs[8] = cpu->bankedRegisters[newFIQBank][2];
33 cpu->gprs[9] = cpu->bankedRegisters[newFIQBank][3];
34 cpu->gprs[10] = cpu->bankedRegisters[newFIQBank][4];
35 cpu->gprs[11] = cpu->bankedRegisters[newFIQBank][5];
36 cpu->gprs[12] = cpu->bankedRegisters[newFIQBank][6];
37 }
38 cpu->bankedRegisters[oldBank][0] = cpu->gprs[ARM_SP];
39 cpu->bankedRegisters[oldBank][1] = cpu->gprs[ARM_LR];
40 cpu->gprs[ARM_SP] = cpu->bankedRegisters[newBank][0];
41 cpu->gprs[ARM_LR] = cpu->bankedRegisters[newBank][1];
42
43 cpu->bankedSPSRs[oldBank] = cpu->spsr.packed;
44 cpu->spsr.packed = cpu->bankedSPSRs[newBank];
45 }
46 cpu->privilegeMode = mode;
47}
48
49static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode mode) {
50 switch (mode) {
51 case MODE_USER:
52 case MODE_SYSTEM:
53 // No banked registers
54 return BANK_NONE;
55 case MODE_FIQ:
56 return BANK_FIQ;
57 case MODE_IRQ:
58 return BANK_IRQ;
59 case MODE_SUPERVISOR:
60 return BANK_SUPERVISOR;
61 case MODE_ABORT:
62 return BANK_ABORT;
63 case MODE_UNDEFINED:
64 return BANK_UNDEFINED;
65 default:
66 // This should be unreached
67 return BANK_NONE;
68 }
69}
70
71void ARMInit(struct ARMCore* cpu) {
72 memset(&cpu->cp15, 0, sizeof(cpu->cp15));
73 cpu->master->init(cpu, cpu->master);
74 size_t i;
75 for (i = 0; i < cpu->numComponents; ++i) {
76 if (cpu->components[i] && cpu->components[i]->init) {
77 cpu->components[i]->init(cpu, cpu->components[i]);
78 }
79 }
80}
81
82void ARMDeinit(struct ARMCore* cpu) {
83 if (cpu->master->deinit) {
84 cpu->master->deinit(cpu->master);
85 }
86 size_t i;
87 for (i = 0; i < cpu->numComponents; ++i) {
88 if (cpu->components[i] && cpu->components[i]->deinit) {
89 cpu->components[i]->deinit(cpu->components[i]);
90 }
91 }
92}
93
94void ARMSetComponents(struct ARMCore* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras) {
95 cpu->master = master;
96 cpu->numComponents = extra;
97 cpu->components = extras;
98}
99
100void ARMHotplugAttach(struct ARMCore* cpu, size_t slot) {
101 if (slot >= cpu->numComponents) {
102 return;
103 }
104 cpu->components[slot]->init(cpu, cpu->components[slot]);
105}
106
107void ARMHotplugDetach(struct ARMCore* cpu, size_t slot) {
108 if (slot >= cpu->numComponents) {
109 return;
110 }
111 cpu->components[slot]->deinit(cpu->components[slot]);
112}
113
114void ARMReset(struct ARMCore* cpu) {
115 int i;
116 for (i = 0; i < 16; ++i) {
117 cpu->gprs[i] = 0;
118 }
119 if (ARMControlRegIsVE(cpu->cp15.r1.c0)) {
120 cpu->gprs[ARM_PC] = 0xFFFF0000;
121 }
122
123 for (i = 0; i < 6; ++i) {
124 cpu->bankedRegisters[i][0] = 0;
125 cpu->bankedRegisters[i][1] = 0;
126 cpu->bankedRegisters[i][2] = 0;
127 cpu->bankedRegisters[i][3] = 0;
128 cpu->bankedRegisters[i][4] = 0;
129 cpu->bankedRegisters[i][5] = 0;
130 cpu->bankedRegisters[i][6] = 0;
131 cpu->bankedSPSRs[i] = 0;
132 }
133
134 cpu->privilegeMode = MODE_SYSTEM;
135 cpu->cpsr.packed = MODE_SYSTEM;
136 cpu->spsr.packed = 0;
137
138 cpu->shifterOperand = 0;
139 cpu->shifterCarryOut = 0;
140
141 cpu->executionMode = MODE_THUMB;
142 _ARMSetMode(cpu, MODE_ARM);
143
144 int currentCycles = 0;
145 ARM_WRITE_PC;
146
147 cpu->cycles = 0;
148 cpu->nextEvent = 0;
149 cpu->halted = 0;
150
151 cpu->irqh.reset(cpu);
152}
153
154void ARMRaiseIRQ(struct ARMCore* cpu) {
155 if (cpu->cpsr.i) {
156 return;
157 }
158 union PSR cpsr = cpu->cpsr;
159 int instructionWidth;
160 if (cpu->executionMode == MODE_THUMB) {
161 instructionWidth = WORD_SIZE_THUMB;
162 } else {
163 instructionWidth = WORD_SIZE_ARM;
164 }
165 ARMSetPrivilegeMode(cpu, MODE_IRQ);
166 cpu->cpsr.priv = MODE_IRQ;
167 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
168 cpu->gprs[ARM_PC] = BASE_IRQ;
169 if (ARMControlRegIsVE(cpu->cp15.r1.c0)) {
170 cpu->gprs[ARM_PC] |= 0xFFFF0000;
171 }
172 int currentCycles = 0;
173 ARM_WRITE_PC;
174 _ARMSetMode(cpu, MODE_ARM);
175 cpu->spsr = cpsr;
176 cpu->cpsr.i = 1;
177 cpu->cycles += currentCycles;
178}
179
180void ARMRaiseSWI(struct ARMCore* cpu) {
181 union PSR cpsr = cpu->cpsr;
182 int instructionWidth;
183 if (cpu->executionMode == MODE_THUMB) {
184 instructionWidth = WORD_SIZE_THUMB;
185 } else {
186 instructionWidth = WORD_SIZE_ARM;
187 }
188 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
189 cpu->cpsr.priv = MODE_SUPERVISOR;
190 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
191 cpu->gprs[ARM_PC] = BASE_SWI;
192 if (ARMControlRegIsVE(cpu->cp15.r1.c0)) {
193 cpu->gprs[ARM_PC] |= 0xFFFF0000;
194 }
195 int currentCycles = 0;
196 ARM_WRITE_PC;
197 _ARMSetMode(cpu, MODE_ARM);
198 cpu->spsr = cpsr;
199 cpu->cpsr.i = 1;
200 cpu->cycles += currentCycles;
201}
202
203void ARMRaiseUndefined(struct ARMCore* cpu) {
204 union PSR cpsr = cpu->cpsr;
205 int instructionWidth;
206 if (cpu->executionMode == MODE_THUMB) {
207 instructionWidth = WORD_SIZE_THUMB;
208 } else {
209 instructionWidth = WORD_SIZE_ARM;
210 }
211 ARMSetPrivilegeMode(cpu, MODE_UNDEFINED);
212 cpu->cpsr.priv = MODE_UNDEFINED;
213 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
214 cpu->gprs[ARM_PC] = BASE_UNDEF;
215 if (ARMControlRegIsVE(cpu->cp15.r1.c0)) {
216 cpu->gprs[ARM_PC] |= 0xFFFF0000;
217 }
218 int currentCycles = 0;
219 ARM_WRITE_PC;
220 _ARMSetMode(cpu, MODE_ARM);
221 cpu->spsr = cpsr;
222 cpu->cpsr.i = 1;
223 cpu->cycles += currentCycles;
224}
225
226void ARMHalt(struct ARMCore* cpu) {
227 cpu->nextEvent = cpu->cycles;
228 cpu->halted = 1;
229}
230
231#define ARM_IMPLEMENT(VERSION) \
232 static inline void ARM ## VERSION ## Step(struct ARMCore* cpu) { \
233 uint32_t opcode = cpu->prefetch[0]; \
234 cpu->prefetch[0] = cpu->prefetch[1]; \
235 cpu->gprs[ARM_PC] += WORD_SIZE_ARM; \
236 LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); \
237 \
238 ARMInstruction instruction; \
239 unsigned condition = opcode >> 28; \
240 if (condition != 0xE) { \
241 bool conditionMet = false; \
242 switch (condition) { \
243 case 0x0: \
244 conditionMet = ARM_COND_EQ; \
245 break; \
246 case 0x1: \
247 conditionMet = ARM_COND_NE; \
248 break; \
249 case 0x2: \
250 conditionMet = ARM_COND_CS; \
251 break; \
252 case 0x3: \
253 conditionMet = ARM_COND_CC; \
254 break; \
255 case 0x4: \
256 conditionMet = ARM_COND_MI; \
257 break; \
258 case 0x5: \
259 conditionMet = ARM_COND_PL; \
260 break; \
261 case 0x6: \
262 conditionMet = ARM_COND_VS; \
263 break; \
264 case 0x7: \
265 conditionMet = ARM_COND_VC; \
266 break; \
267 case 0x8: \
268 conditionMet = ARM_COND_HI; \
269 break; \
270 case 0x9: \
271 conditionMet = ARM_COND_LS; \
272 break; \
273 case 0xA: \
274 conditionMet = ARM_COND_GE; \
275 break; \
276 case 0xB: \
277 conditionMet = ARM_COND_LT; \
278 break; \
279 case 0xC: \
280 conditionMet = ARM_COND_GT; \
281 break; \
282 case 0xD: \
283 conditionMet = ARM_COND_LE; \
284 break; \
285 default: \
286 instruction = _arm ## VERSION ## FTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; \
287 instruction(cpu, opcode); \
288 return; \
289 } \
290 if (!conditionMet) { \
291 cpu->cycles += ARM_PREFETCH_CYCLES; \
292 return; \
293 } \
294 } \
295 instruction = _arm ## VERSION ## Table[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; \
296 instruction(cpu, opcode); \
297 } \
298 \
299 static inline void Thumb ## VERSION ## Step(struct ARMCore* cpu) { \
300 uint32_t opcode = cpu->prefetch[0]; \
301 cpu->prefetch[0] = cpu->prefetch[1]; \
302 cpu->gprs[ARM_PC] += WORD_SIZE_THUMB; \
303 LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); \
304 ThumbInstruction instruction = _thumb ## VERSION ## Table[opcode >> 6]; \
305 instruction(cpu, opcode); \
306 } \
307 \
308 void ARM ## VERSION ## Run(struct ARMCore* cpu) { \
309 if (cpu->cycles < cpu->nextEvent) { \
310 if (cpu->executionMode == MODE_THUMB) { \
311 Thumb ## VERSION ## Step(cpu); \
312 } else { \
313 ARM ## VERSION ## Step(cpu); \
314 } \
315 } \
316 if (cpu->cycles >= cpu->nextEvent) { \
317 cpu->irqh.processEvents(cpu); \
318 } \
319 } \
320 \
321 void ARM ## VERSION ## RunLoop(struct ARMCore* cpu) { \
322 if (cpu->executionMode == MODE_THUMB) { \
323 while (cpu->cycles < cpu->nextEvent) { \
324 Thumb ## VERSION ## Step(cpu); \
325 } \
326 } else { \
327 while (cpu->cycles < cpu->nextEvent) { \
328 ARM ## VERSION ## Step(cpu); \
329 } \
330 } \
331 cpu->irqh.processEvents(cpu); \
332 }
333
334ARM_IMPLEMENT(v4)
335ARM_IMPLEMENT(v5)
336
337void ARMRunFake(struct ARMCore* cpu, uint32_t opcode) {
338 if (cpu->executionMode == MODE_ARM) {
339 cpu->gprs[ARM_PC] -= WORD_SIZE_ARM;
340 } else {
341 cpu->gprs[ARM_PC] -= WORD_SIZE_THUMB;
342 }
343 cpu->prefetch[1] = cpu->prefetch[0];
344 cpu->prefetch[0] = opcode;
345}