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 
12 static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode);
13 
ARMSetPrivilegeMode(struct ARMCore * cpu,enum PrivilegeMode mode)14 void 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 
_ARMSelectBank(enum PrivilegeMode mode)49 static 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 
ARMInit(struct ARMCore * cpu)71 void ARMInit(struct ARMCore* cpu) {
72 	cpu->master->init(cpu, cpu->master);
73 	size_t i;
74 	for (i = 0; i < cpu->numComponents; ++i) {
75 		if (cpu->components[i] && cpu->components[i]->init) {
76 			cpu->components[i]->init(cpu, cpu->components[i]);
77 		}
78 	}
79 }
80 
ARMDeinit(struct ARMCore * cpu)81 void ARMDeinit(struct ARMCore* cpu) {
82 	if (cpu->master->deinit) {
83 		cpu->master->deinit(cpu->master);
84 	}
85 	size_t i;
86 	for (i = 0; i < cpu->numComponents; ++i) {
87 		if (cpu->components[i] && cpu->components[i]->deinit) {
88 			cpu->components[i]->deinit(cpu->components[i]);
89 		}
90 	}
91 }
92 
ARMSetComponents(struct ARMCore * cpu,struct mCPUComponent * master,int extra,struct mCPUComponent ** extras)93 void ARMSetComponents(struct ARMCore* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras) {
94 	cpu->master = master;
95 	cpu->numComponents = extra;
96 	cpu->components = extras;
97 }
98 
ARMHotplugAttach(struct ARMCore * cpu,size_t slot)99 void ARMHotplugAttach(struct ARMCore* cpu, size_t slot) {
100 	if (slot >= cpu->numComponents) {
101 		return;
102 	}
103 	cpu->components[slot]->init(cpu, cpu->components[slot]);
104 }
105 
ARMHotplugDetach(struct ARMCore * cpu,size_t slot)106 void ARMHotplugDetach(struct ARMCore* cpu, size_t slot) {
107 	if (slot >= cpu->numComponents) {
108 		return;
109 	}
110 	cpu->components[slot]->deinit(cpu->components[slot]);
111 }
112 
ARMReset(struct ARMCore * cpu)113 void ARMReset(struct ARMCore* cpu) {
114 	int i;
115 	for (i = 0; i < 16; ++i) {
116 		cpu->gprs[i] = 0;
117 	}
118 	for (i = 0; i < 6; ++i) {
119 		cpu->bankedRegisters[i][0] = 0;
120 		cpu->bankedRegisters[i][1] = 0;
121 		cpu->bankedRegisters[i][2] = 0;
122 		cpu->bankedRegisters[i][3] = 0;
123 		cpu->bankedRegisters[i][4] = 0;
124 		cpu->bankedRegisters[i][5] = 0;
125 		cpu->bankedRegisters[i][6] = 0;
126 		cpu->bankedSPSRs[i] = 0;
127 	}
128 
129 	cpu->privilegeMode = MODE_SYSTEM;
130 	cpu->cpsr.packed = MODE_SYSTEM;
131 	cpu->spsr.packed = 0;
132 
133 	cpu->shifterOperand = 0;
134 	cpu->shifterCarryOut = 0;
135 
136 	cpu->executionMode = MODE_THUMB;
137 	_ARMSetMode(cpu, MODE_ARM);
138 	ARMWritePC(cpu);
139 
140 	cpu->cycles = 0;
141 	cpu->nextEvent = 0;
142 	cpu->halted = 0;
143 
144 	cpu->irqh.reset(cpu);
145 }
146 
ARMRaiseIRQ(struct ARMCore * cpu)147 void ARMRaiseIRQ(struct ARMCore* cpu) {
148 	if (cpu->cpsr.i) {
149 		return;
150 	}
151 	union PSR cpsr = cpu->cpsr;
152 	int instructionWidth;
153 	if (cpu->executionMode == MODE_THUMB) {
154 		instructionWidth = WORD_SIZE_THUMB;
155 	} else {
156 		instructionWidth = WORD_SIZE_ARM;
157 	}
158 	ARMSetPrivilegeMode(cpu, MODE_IRQ);
159 	cpu->cpsr.priv = MODE_IRQ;
160 	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
161 	cpu->gprs[ARM_PC] = BASE_IRQ;
162 	_ARMSetMode(cpu, MODE_ARM);
163 	cpu->cycles += ARMWritePC(cpu);
164 	cpu->spsr = cpsr;
165 	cpu->cpsr.i = 1;
166 	cpu->halted = 0;
167 }
168 
ARMRaiseSWI(struct ARMCore * cpu)169 void ARMRaiseSWI(struct ARMCore* cpu) {
170 	union PSR cpsr = cpu->cpsr;
171 	int instructionWidth;
172 	if (cpu->executionMode == MODE_THUMB) {
173 		instructionWidth = WORD_SIZE_THUMB;
174 	} else {
175 		instructionWidth = WORD_SIZE_ARM;
176 	}
177 	ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
178 	cpu->cpsr.priv = MODE_SUPERVISOR;
179 	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
180 	cpu->gprs[ARM_PC] = BASE_SWI;
181 	_ARMSetMode(cpu, MODE_ARM);
182 	cpu->cycles += ARMWritePC(cpu);
183 	cpu->spsr = cpsr;
184 	cpu->cpsr.i = 1;
185 }
186 
ARMRaiseUndefined(struct ARMCore * cpu)187 void ARMRaiseUndefined(struct ARMCore* cpu) {
188 	union PSR cpsr = cpu->cpsr;
189 	int instructionWidth;
190 	if (cpu->executionMode == MODE_THUMB) {
191 		instructionWidth = WORD_SIZE_THUMB;
192 	} else {
193 		instructionWidth = WORD_SIZE_ARM;
194 	}
195 	ARMSetPrivilegeMode(cpu, MODE_UNDEFINED);
196 	cpu->cpsr.priv = MODE_UNDEFINED;
197 	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
198 	cpu->gprs[ARM_PC] = BASE_UNDEF;
199 	_ARMSetMode(cpu, MODE_ARM);
200 	cpu->cycles += ARMWritePC(cpu);
201 	cpu->spsr = cpsr;
202 	cpu->cpsr.i = 1;
203 }
204 
ARMStep(struct ARMCore * cpu)205 static inline void ARMStep(struct ARMCore* cpu) {
206 	uint32_t opcode = cpu->prefetch[0];
207 	cpu->prefetch[0] = cpu->prefetch[1];
208 	cpu->gprs[ARM_PC] += WORD_SIZE_ARM;
209 	LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
210 
211 	unsigned condition = opcode >> 28;
212 	if (condition != 0xE) {
213 		bool conditionMet = false;
214 		switch (condition) {
215 		case 0x0:
216 			conditionMet = ARM_COND_EQ;
217 			break;
218 		case 0x1:
219 			conditionMet = ARM_COND_NE;
220 			break;
221 		case 0x2:
222 			conditionMet = ARM_COND_CS;
223 			break;
224 		case 0x3:
225 			conditionMet = ARM_COND_CC;
226 			break;
227 		case 0x4:
228 			conditionMet = ARM_COND_MI;
229 			break;
230 		case 0x5:
231 			conditionMet = ARM_COND_PL;
232 			break;
233 		case 0x6:
234 			conditionMet = ARM_COND_VS;
235 			break;
236 		case 0x7:
237 			conditionMet = ARM_COND_VC;
238 			break;
239 		case 0x8:
240 			conditionMet = ARM_COND_HI;
241 			break;
242 		case 0x9:
243 			conditionMet = ARM_COND_LS;
244 			break;
245 		case 0xA:
246 			conditionMet = ARM_COND_GE;
247 			break;
248 		case 0xB:
249 			conditionMet = ARM_COND_LT;
250 			break;
251 		case 0xC:
252 			conditionMet = ARM_COND_GT;
253 			break;
254 		case 0xD:
255 			conditionMet = ARM_COND_LE;
256 			break;
257 		default:
258 			break;
259 		}
260 		if (!conditionMet) {
261 			cpu->cycles += ARM_PREFETCH_CYCLES;
262 			return;
263 		}
264 	}
265 	ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
266 	instruction(cpu, opcode);
267 }
268 
ThumbStep(struct ARMCore * cpu)269 static inline void ThumbStep(struct ARMCore* cpu) {
270 	uint32_t opcode = cpu->prefetch[0];
271 	cpu->prefetch[0] = cpu->prefetch[1];
272 	cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
273 	LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
274 	ThumbInstruction instruction = _thumbTable[opcode >> 6];
275 	instruction(cpu, opcode);
276 }
277 
ARMRun(struct ARMCore * cpu)278 void ARMRun(struct ARMCore* cpu) {
279 	while (cpu->cycles >= cpu->nextEvent) {
280 		cpu->irqh.processEvents(cpu);
281 	}
282 	if (cpu->executionMode == MODE_THUMB) {
283 		ThumbStep(cpu);
284 	} else {
285 		ARMStep(cpu);
286 	}
287 }
288 
ARMRunLoop(struct ARMCore * cpu)289 void ARMRunLoop(struct ARMCore* cpu) {
290 	if (cpu->executionMode == MODE_THUMB) {
291 		while (cpu->cycles < cpu->nextEvent) {
292 			ThumbStep(cpu);
293 		}
294 	} else {
295 		while (cpu->cycles < cpu->nextEvent) {
296 			ARMStep(cpu);
297 		}
298 	}
299 	cpu->irqh.processEvents(cpu);
300 }
301 
ARMRunFake(struct ARMCore * cpu,uint32_t opcode)302 void ARMRunFake(struct ARMCore* cpu, uint32_t opcode) {
303 	if (cpu->executionMode == MODE_ARM) {
304 		cpu->gprs[ARM_PC] -= WORD_SIZE_ARM;
305 	} else {
306 		cpu->gprs[ARM_PC] -= WORD_SIZE_THUMB;
307 	}
308 	cpu->prefetch[1] = cpu->prefetch[0];
309 	cpu->prefetch[0] = opcode;
310 }
311