src/arm/arm.c (view raw)
1/* Copyright (c) 2013-2014 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
12void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
13 if (mode == cpu->privilegeMode) {
14 // Not switching modes after all
15 return;
16 }
17
18 enum RegisterBank newBank = ARMSelectBank(mode);
19 enum RegisterBank oldBank = ARMSelectBank(cpu->privilegeMode);
20 if (newBank != oldBank) {
21 // Switch banked registers
22 if (mode == MODE_FIQ || cpu->privilegeMode == MODE_FIQ) {
23 int oldFIQBank = oldBank == BANK_FIQ;
24 int newFIQBank = newBank == BANK_FIQ;
25 cpu->bankedRegisters[oldFIQBank][2] = cpu->gprs[8];
26 cpu->bankedRegisters[oldFIQBank][3] = cpu->gprs[9];
27 cpu->bankedRegisters[oldFIQBank][4] = cpu->gprs[10];
28 cpu->bankedRegisters[oldFIQBank][5] = cpu->gprs[11];
29 cpu->bankedRegisters[oldFIQBank][6] = cpu->gprs[12];
30 cpu->gprs[8] = cpu->bankedRegisters[newFIQBank][2];
31 cpu->gprs[9] = cpu->bankedRegisters[newFIQBank][3];
32 cpu->gprs[10] = cpu->bankedRegisters[newFIQBank][4];
33 cpu->gprs[11] = cpu->bankedRegisters[newFIQBank][5];
34 cpu->gprs[12] = cpu->bankedRegisters[newFIQBank][6];
35 }
36 cpu->bankedRegisters[oldBank][0] = cpu->gprs[ARM_SP];
37 cpu->bankedRegisters[oldBank][1] = cpu->gprs[ARM_LR];
38 cpu->gprs[ARM_SP] = cpu->bankedRegisters[newBank][0];
39 cpu->gprs[ARM_LR] = cpu->bankedRegisters[newBank][1];
40
41 cpu->bankedSPSRs[oldBank] = cpu->spsr.packed;
42 cpu->spsr.packed = cpu->bankedSPSRs[newBank];
43 }
44 cpu->privilegeMode = mode;
45}
46
47void ARMInit(struct ARMCore* cpu) {
48 cpu->master->init(cpu, cpu->master);
49 size_t i;
50 for (i = 0; i < cpu->numComponents; ++i) {
51 if (cpu->components[i] && cpu->components[i]->init) {
52 cpu->components[i]->init(cpu, cpu->components[i]);
53 }
54 }
55}
56
57void ARMDeinit(struct ARMCore* cpu) {
58 if (cpu->master->deinit) {
59 cpu->master->deinit(cpu->master);
60 }
61 size_t i;
62 for (i = 0; i < cpu->numComponents; ++i) {
63 if (cpu->components[i] && cpu->components[i]->deinit) {
64 cpu->components[i]->deinit(cpu->components[i]);
65 }
66 }
67}
68
69void ARMSetComponents(struct ARMCore* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras) {
70 cpu->master = master;
71 cpu->numComponents = extra;
72 cpu->components = extras;
73}
74
75void ARMHotplugAttach(struct ARMCore* cpu, size_t slot) {
76 if (slot >= cpu->numComponents) {
77 return;
78 }
79 cpu->components[slot]->init(cpu, cpu->components[slot]);
80}
81
82void ARMHotplugDetach(struct ARMCore* cpu, size_t slot) {
83 if (slot >= cpu->numComponents) {
84 return;
85 }
86 cpu->components[slot]->deinit(cpu->components[slot]);
87}
88
89void ARMReset(struct ARMCore* cpu) {
90 int i;
91 for (i = 0; i < 16; ++i) {
92 cpu->gprs[i] = 0;
93 }
94 for (i = 0; i < 6; ++i) {
95 cpu->bankedRegisters[i][0] = 0;
96 cpu->bankedRegisters[i][1] = 0;
97 cpu->bankedRegisters[i][2] = 0;
98 cpu->bankedRegisters[i][3] = 0;
99 cpu->bankedRegisters[i][4] = 0;
100 cpu->bankedRegisters[i][5] = 0;
101 cpu->bankedRegisters[i][6] = 0;
102 cpu->bankedSPSRs[i] = 0;
103 }
104
105 cpu->privilegeMode = MODE_SYSTEM;
106 cpu->cpsr.packed = MODE_SYSTEM;
107 cpu->spsr.packed = 0;
108
109 cpu->shifterOperand = 0;
110 cpu->shifterCarryOut = 0;
111
112 cpu->executionMode = MODE_THUMB;
113 _ARMSetMode(cpu, MODE_ARM);
114 ARMWritePC(cpu);
115
116 cpu->cycles = 0;
117 cpu->nextEvent = 0;
118 cpu->halted = 0;
119
120 cpu->irqh.reset(cpu);
121}
122
123void ARMRaiseIRQ(struct ARMCore* cpu) {
124 if (cpu->cpsr.i) {
125 return;
126 }
127 union PSR cpsr = cpu->cpsr;
128 int instructionWidth;
129 if (cpu->executionMode == MODE_THUMB) {
130 instructionWidth = WORD_SIZE_THUMB;
131 } else {
132 instructionWidth = WORD_SIZE_ARM;
133 }
134 ARMSetPrivilegeMode(cpu, MODE_IRQ);
135 cpu->cpsr.priv = MODE_IRQ;
136 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
137 cpu->gprs[ARM_PC] = BASE_IRQ;
138 _ARMSetMode(cpu, MODE_ARM);
139 cpu->cycles += ARMWritePC(cpu);
140 cpu->spsr = cpsr;
141 cpu->cpsr.i = 1;
142 cpu->halted = 0;
143}
144
145void ARMRaiseSWI(struct ARMCore* cpu) {
146 union PSR cpsr = cpu->cpsr;
147 int instructionWidth;
148 if (cpu->executionMode == MODE_THUMB) {
149 instructionWidth = WORD_SIZE_THUMB;
150 } else {
151 instructionWidth = WORD_SIZE_ARM;
152 }
153 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
154 cpu->cpsr.priv = MODE_SUPERVISOR;
155 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
156 cpu->gprs[ARM_PC] = BASE_SWI;
157 _ARMSetMode(cpu, MODE_ARM);
158 cpu->cycles += ARMWritePC(cpu);
159 cpu->spsr = cpsr;
160 cpu->cpsr.i = 1;
161}
162
163void ARMRaiseUndefined(struct ARMCore* cpu) {
164 union PSR cpsr = cpu->cpsr;
165 int instructionWidth;
166 if (cpu->executionMode == MODE_THUMB) {
167 instructionWidth = WORD_SIZE_THUMB;
168 } else {
169 instructionWidth = WORD_SIZE_ARM;
170 }
171 ARMSetPrivilegeMode(cpu, MODE_UNDEFINED);
172 cpu->cpsr.priv = MODE_UNDEFINED;
173 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
174 cpu->gprs[ARM_PC] = BASE_UNDEF;
175 _ARMSetMode(cpu, MODE_ARM);
176 cpu->cycles += ARMWritePC(cpu);
177 cpu->spsr = cpsr;
178 cpu->cpsr.i = 1;
179}
180
181static inline void ARMStep(struct ARMCore* cpu) {
182 uint32_t opcode = cpu->prefetch[0];
183 cpu->prefetch[0] = cpu->prefetch[1];
184 cpu->gprs[ARM_PC] += WORD_SIZE_ARM;
185 LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
186
187 unsigned condition = opcode >> 28;
188 if (condition != 0xE) {
189 bool conditionMet = false;
190 switch (condition) {
191 case 0x0:
192 conditionMet = ARM_COND_EQ;
193 break;
194 case 0x1:
195 conditionMet = ARM_COND_NE;
196 break;
197 case 0x2:
198 conditionMet = ARM_COND_CS;
199 break;
200 case 0x3:
201 conditionMet = ARM_COND_CC;
202 break;
203 case 0x4:
204 conditionMet = ARM_COND_MI;
205 break;
206 case 0x5:
207 conditionMet = ARM_COND_PL;
208 break;
209 case 0x6:
210 conditionMet = ARM_COND_VS;
211 break;
212 case 0x7:
213 conditionMet = ARM_COND_VC;
214 break;
215 case 0x8:
216 conditionMet = ARM_COND_HI;
217 break;
218 case 0x9:
219 conditionMet = ARM_COND_LS;
220 break;
221 case 0xA:
222 conditionMet = ARM_COND_GE;
223 break;
224 case 0xB:
225 conditionMet = ARM_COND_LT;
226 break;
227 case 0xC:
228 conditionMet = ARM_COND_GT;
229 break;
230 case 0xD:
231 conditionMet = ARM_COND_LE;
232 break;
233 default:
234 break;
235 }
236 if (!conditionMet) {
237 cpu->cycles += ARM_PREFETCH_CYCLES;
238 return;
239 }
240 }
241 ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
242 instruction(cpu, opcode);
243}
244
245static inline void ThumbStep(struct ARMCore* cpu) {
246 uint32_t opcode = cpu->prefetch[0];
247 cpu->prefetch[0] = cpu->prefetch[1];
248 cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
249 LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
250 ThumbInstruction instruction = _thumbTable[opcode >> 6];
251 instruction(cpu, opcode);
252}
253
254void ARMRun(struct ARMCore* cpu) {
255 while (cpu->cycles >= cpu->nextEvent) {
256 cpu->irqh.processEvents(cpu);
257 }
258 if (cpu->executionMode == MODE_THUMB) {
259 ThumbStep(cpu);
260 } else {
261 ARMStep(cpu);
262 }
263}
264
265void ARMRunLoop(struct ARMCore* cpu) {
266 if (cpu->executionMode == MODE_THUMB) {
267 while (cpu->cycles < cpu->nextEvent) {
268 ThumbStep(cpu);
269 }
270 } else {
271 while (cpu->cycles < cpu->nextEvent) {
272 ARMStep(cpu);
273 }
274 }
275 cpu->irqh.processEvents(cpu);
276}
277
278void ARMRunFake(struct ARMCore* cpu, uint32_t opcode) {
279 if (cpu->executionMode == MODE_ARM) {
280 cpu->gprs[ARM_PC] -= WORD_SIZE_ARM;
281 } else {
282 cpu->gprs[ARM_PC] -= WORD_SIZE_THUMB;
283 }
284 cpu->prefetch[1] = cpu->prefetch[0];
285 cpu->prefetch[0] = opcode;
286}