all repos — mgba @ 5f8548b8dca9a8e8979c1996ed8333e5dc043420

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