all repos — mgba @ 6d898542c765f4efc4a094c5ebd3f3465c36f417

mGBA Game Boy Advance Emulator

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	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	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
 81void 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
 93void 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
 99void 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
106void 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
113void 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
139	int currentCycles = 0;
140	ARM_WRITE_PC;
141
142	cpu->cycles = 0;
143	cpu->nextEvent = 0;
144	cpu->halted = 0;
145
146	cpu->irqh.reset(cpu);
147}
148
149void ARMRaiseIRQ(struct ARMCore* cpu) {
150	if (cpu->cpsr.i) {
151		return;
152	}
153	union PSR cpsr = cpu->cpsr;
154	int instructionWidth;
155	if (cpu->executionMode == MODE_THUMB) {
156		instructionWidth = WORD_SIZE_THUMB;
157	} else {
158		instructionWidth = WORD_SIZE_ARM;
159	}
160	ARMSetPrivilegeMode(cpu, MODE_IRQ);
161	cpu->cpsr.priv = MODE_IRQ;
162	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
163	cpu->gprs[ARM_PC] = BASE_IRQ;
164	int currentCycles = 0;
165	ARM_WRITE_PC;
166	_ARMSetMode(cpu, MODE_ARM);
167	cpu->spsr = cpsr;
168	cpu->cpsr.i = 1;
169	cpu->cycles += currentCycles;
170}
171
172void ARMRaiseSWI(struct ARMCore* cpu) {
173	union PSR cpsr = cpu->cpsr;
174	int instructionWidth;
175	if (cpu->executionMode == MODE_THUMB) {
176		instructionWidth = WORD_SIZE_THUMB;
177	} else {
178		instructionWidth = WORD_SIZE_ARM;
179	}
180	ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
181	cpu->cpsr.priv = MODE_SUPERVISOR;
182	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
183	cpu->gprs[ARM_PC] = BASE_SWI;
184	int currentCycles = 0;
185	ARM_WRITE_PC;
186	_ARMSetMode(cpu, MODE_ARM);
187	cpu->spsr = cpsr;
188	cpu->cpsr.i = 1;
189	cpu->cycles += currentCycles;
190}
191
192void ARMRaiseUndefined(struct ARMCore* cpu) {
193	union PSR cpsr = cpu->cpsr;
194	int instructionWidth;
195	if (cpu->executionMode == MODE_THUMB) {
196		instructionWidth = WORD_SIZE_THUMB;
197	} else {
198		instructionWidth = WORD_SIZE_ARM;
199	}
200	ARMSetPrivilegeMode(cpu, MODE_UNDEFINED);
201	cpu->cpsr.priv = MODE_UNDEFINED;
202	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
203	cpu->gprs[ARM_PC] = BASE_UNDEF;
204	int currentCycles = 0;
205	ARM_WRITE_PC;
206	_ARMSetMode(cpu, MODE_ARM);
207	cpu->spsr = cpsr;
208	cpu->cpsr.i = 1;
209	cpu->cycles += currentCycles;
210}
211
212static inline void ARMStep(struct ARMCore* cpu) {
213	uint32_t opcode = cpu->prefetch[0];
214	cpu->prefetch[0] = cpu->prefetch[1];
215	cpu->gprs[ARM_PC] += WORD_SIZE_ARM;
216	LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
217
218	unsigned condition = opcode >> 28;
219	if (condition != 0xE) {
220		bool conditionMet = false;
221		switch (condition) {
222		case 0x0:
223			conditionMet = ARM_COND_EQ;
224			break;
225		case 0x1:
226			conditionMet = ARM_COND_NE;
227			break;
228		case 0x2:
229			conditionMet = ARM_COND_CS;
230			break;
231		case 0x3:
232			conditionMet = ARM_COND_CC;
233			break;
234		case 0x4:
235			conditionMet = ARM_COND_MI;
236			break;
237		case 0x5:
238			conditionMet = ARM_COND_PL;
239			break;
240		case 0x6:
241			conditionMet = ARM_COND_VS;
242			break;
243		case 0x7:
244			conditionMet = ARM_COND_VC;
245			break;
246		case 0x8:
247			conditionMet = ARM_COND_HI;
248			break;
249		case 0x9:
250			conditionMet = ARM_COND_LS;
251			break;
252		case 0xA:
253			conditionMet = ARM_COND_GE;
254			break;
255		case 0xB:
256			conditionMet = ARM_COND_LT;
257			break;
258		case 0xC:
259			conditionMet = ARM_COND_GT;
260			break;
261		case 0xD:
262			conditionMet = ARM_COND_LE;
263			break;
264		default:
265			break;
266		}
267		if (!conditionMet) {
268			cpu->cycles += ARM_PREFETCH_CYCLES;
269			return;
270		}
271	}
272	ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
273	instruction(cpu, opcode);
274}
275
276static inline void ThumbStep(struct ARMCore* cpu) {
277	uint32_t opcode = cpu->prefetch[0];
278	cpu->prefetch[0] = cpu->prefetch[1];
279	cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
280	LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
281	ThumbInstruction instruction = _thumbTable[opcode >> 6];
282	instruction(cpu, opcode);
283}
284
285void ARMRun(struct ARMCore* cpu) {
286	if (cpu->executionMode == MODE_THUMB) {
287		ThumbStep(cpu);
288	} else {
289		ARMStep(cpu);
290	}
291	if (cpu->cycles >= cpu->nextEvent) {
292		cpu->irqh.processEvents(cpu);
293	}
294}
295
296void ARMRunLoop(struct ARMCore* cpu) {
297	if (cpu->executionMode == MODE_THUMB) {
298		while (cpu->cycles < cpu->nextEvent) {
299			ThumbStep(cpu);
300		}
301	} else {
302		while (cpu->cycles < cpu->nextEvent) {
303			ARMStep(cpu);
304		}
305	}
306	cpu->irqh.processEvents(cpu);
307}
308
309void ARMRunFake(struct ARMCore* cpu, uint32_t opcode) {
310	if (cpu->executionMode == MODE_ARM) {
311		cpu->gprs[ARM_PC] -= WORD_SIZE_ARM;
312	} else {
313		cpu->gprs[ARM_PC] -= WORD_SIZE_THUMB;
314	}
315	cpu->prefetch[1] = cpu->prefetch[0];
316	cpu->prefetch[0] = opcode;
317}