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 "arm.h"
7
8#include "isa-arm.h"
9#include "isa-inlines.h"
10#include "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 }
47 cpu->privilegeMode = mode;
48}
49
50static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode mode) {
51 switch (mode) {
52 case MODE_USER:
53 case MODE_SYSTEM:
54 // No banked registers
55 return BANK_NONE;
56 case MODE_FIQ:
57 return BANK_FIQ;
58 case MODE_IRQ:
59 return BANK_IRQ;
60 case MODE_SUPERVISOR:
61 return BANK_SUPERVISOR;
62 case MODE_ABORT:
63 return BANK_ABORT;
64 case MODE_UNDEFINED:
65 return BANK_UNDEFINED;
66 default:
67 // This should be unreached
68 return BANK_NONE;
69 }
70}
71
72void ARMInit(struct ARMCore* cpu) {
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 ARMComponent* master, int extra, struct ARMComponent** 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]->init(cpu, 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 for (i = 0; i < 6; ++i) {
120 cpu->bankedRegisters[i][0] = 0;
121 cpu->bankedRegisters[i][1] = 0;
122 cpu->bankedRegisters[i][2] = 0;
123 cpu->bankedRegisters[i][3] = 0;
124 cpu->bankedRegisters[i][4] = 0;
125 cpu->bankedRegisters[i][5] = 0;
126 cpu->bankedRegisters[i][6] = 0;
127 cpu->bankedSPSRs[i] = 0;
128 }
129
130 cpu->privilegeMode = MODE_SYSTEM;
131 cpu->cpsr.packed = MODE_SYSTEM;
132 cpu->spsr.packed = 0;
133
134 cpu->shifterOperand = 0;
135 cpu->shifterCarryOut = 0;
136
137 cpu->executionMode = MODE_THUMB;
138 _ARMSetMode(cpu, MODE_ARM);
139
140 int currentCycles = 0;
141 ARM_WRITE_PC;
142
143 cpu->cycles = 0;
144 cpu->nextEvent = 0;
145 cpu->halted = 0;
146
147 cpu->irqh.reset(cpu);
148}
149
150void ARMRaiseIRQ(struct ARMCore* cpu) {
151 if (cpu->cpsr.i) {
152 return;
153 }
154 union PSR cpsr = cpu->cpsr;
155 int instructionWidth;
156 if (cpu->executionMode == MODE_THUMB) {
157 instructionWidth = WORD_SIZE_THUMB;
158 } else {
159 instructionWidth = WORD_SIZE_ARM;
160 }
161 ARMSetPrivilegeMode(cpu, MODE_IRQ);
162 cpu->cpsr.priv = MODE_IRQ;
163 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
164 cpu->gprs[ARM_PC] = BASE_IRQ;
165 int currentCycles = 0;
166 ARM_WRITE_PC;
167 _ARMSetMode(cpu, MODE_ARM);
168 cpu->spsr = cpsr;
169 cpu->cpsr.i = 1;
170 cpu->cycles += currentCycles;
171}
172
173void ARMRaiseSWI(struct ARMCore* cpu) {
174 union PSR cpsr = cpu->cpsr;
175 int instructionWidth;
176 if (cpu->executionMode == MODE_THUMB) {
177 instructionWidth = WORD_SIZE_THUMB;
178 } else {
179 instructionWidth = WORD_SIZE_ARM;
180 }
181 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
182 cpu->cpsr.priv = MODE_SUPERVISOR;
183 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
184 cpu->gprs[ARM_PC] = BASE_SWI;
185 int currentCycles = 0;
186 ARM_WRITE_PC;
187 _ARMSetMode(cpu, MODE_ARM);
188 cpu->spsr = cpsr;
189 cpu->cpsr.i = 1;
190 cpu->cycles += currentCycles;
191}
192
193void ARMRaiseUndefined(struct ARMCore* cpu) {
194 union PSR cpsr = cpu->cpsr;
195 int instructionWidth;
196 if (cpu->executionMode == MODE_THUMB) {
197 instructionWidth = WORD_SIZE_THUMB;
198 } else {
199 instructionWidth = WORD_SIZE_ARM;
200 }
201 ARMSetPrivilegeMode(cpu, MODE_UNDEFINED);
202 cpu->cpsr.priv = MODE_UNDEFINED;
203 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
204 cpu->gprs[ARM_PC] = BASE_UNDEF;
205 int currentCycles = 0;
206 ARM_WRITE_PC;
207 _ARMSetMode(cpu, MODE_ARM);
208 cpu->spsr = cpsr;
209 cpu->cpsr.i = 1;
210 cpu->cycles += currentCycles;
211}
212
213static inline void ARMStep(struct ARMCore* cpu) {
214 uint32_t opcode = cpu->prefetch[0];
215 cpu->prefetch[0] = cpu->prefetch[1];
216 cpu->gprs[ARM_PC] += WORD_SIZE_ARM;
217 LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
218
219 unsigned condition = opcode >> 28;
220 if (condition != 0xE) {
221 bool conditionMet = false;
222 switch (condition) {
223 case 0x0:
224 conditionMet = ARM_COND_EQ;
225 break;
226 case 0x1:
227 conditionMet = ARM_COND_NE;
228 break;
229 case 0x2:
230 conditionMet = ARM_COND_CS;
231 break;
232 case 0x3:
233 conditionMet = ARM_COND_CC;
234 break;
235 case 0x4:
236 conditionMet = ARM_COND_MI;
237 break;
238 case 0x5:
239 conditionMet = ARM_COND_PL;
240 break;
241 case 0x6:
242 conditionMet = ARM_COND_VS;
243 break;
244 case 0x7:
245 conditionMet = ARM_COND_VC;
246 break;
247 case 0x8:
248 conditionMet = ARM_COND_HI;
249 break;
250 case 0x9:
251 conditionMet = ARM_COND_LS;
252 break;
253 case 0xA:
254 conditionMet = ARM_COND_GE;
255 break;
256 case 0xB:
257 conditionMet = ARM_COND_LT;
258 break;
259 case 0xC:
260 conditionMet = ARM_COND_GT;
261 break;
262 case 0xD:
263 conditionMet = ARM_COND_LE;
264 break;
265 default:
266 break;
267 }
268 if (!conditionMet) {
269 cpu->cycles += ARM_PREFETCH_CYCLES;
270 return;
271 }
272 }
273 ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
274 instruction(cpu, opcode);
275}
276
277static inline void ThumbStep(struct ARMCore* cpu) {
278 uint32_t opcode = cpu->prefetch[0];
279 cpu->prefetch[0] = cpu->prefetch[1];
280 cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
281 LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
282 ThumbInstruction instruction = _thumbTable[opcode >> 6];
283 instruction(cpu, opcode);
284}
285
286void ARMRun(struct ARMCore* cpu) {
287 if (cpu->executionMode == MODE_THUMB) {
288 ThumbStep(cpu);
289 } else {
290 ARMStep(cpu);
291 }
292 if (cpu->cycles >= cpu->nextEvent) {
293 cpu->irqh.processEvents(cpu);
294 }
295}
296
297void ARMRunLoop(struct ARMCore* cpu) {
298 if (cpu->executionMode == MODE_THUMB) {
299 while (cpu->cycles < cpu->nextEvent) {
300 ThumbStep(cpu);
301 }
302 } else {
303 while (cpu->cycles < cpu->nextEvent) {
304 ARMStep(cpu);
305 }
306 }
307 cpu->irqh.processEvents(cpu);
308}
309
310void ARMRunFake(struct ARMCore* cpu, uint32_t opcode) {
311 if (cpu->executionMode== MODE_ARM) {
312 cpu->gprs[ARM_PC] -= WORD_SIZE_ARM;
313 } else {
314 cpu->gprs[ARM_PC] -= WORD_SIZE_THUMB;
315 }
316 cpu->prefetch[1] = cpu->prefetch[0];
317 cpu->prefetch[0] = opcode;
318}