all repos — mgba @ 830511472a3d3e9854b94216fc4e74e35d8d3081

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