all repos — mgba @ 07667955f66e4d00b0f5421f2d08186109211080

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 <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}