all repos — mgba @ 4d2ccd5df438b988c21af6959c3704aec590a075

mGBA Game Boy Advance Emulator

src/arm/arm.c (view raw)

  1#include "arm.h"
  2
  3#include "isa-arm.h"
  4#include "isa-inlines.h"
  5#include "isa-thumb.h"
  6
  7static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode);
  8
  9void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
 10	if (mode == cpu->privilegeMode) {
 11		// Not switching modes after all
 12		return;
 13	}
 14
 15	enum RegisterBank newBank = _ARMSelectBank(mode);
 16	enum RegisterBank oldBank = _ARMSelectBank(cpu->privilegeMode);
 17	if (newBank != oldBank) {
 18		// Switch banked registers
 19		if (mode == MODE_FIQ || cpu->privilegeMode == MODE_FIQ) {
 20			int oldFIQBank = oldBank == BANK_FIQ;
 21			int newFIQBank = newBank == BANK_FIQ;
 22			cpu->bankedRegisters[oldFIQBank][2] = cpu->gprs[8];
 23			cpu->bankedRegisters[oldFIQBank][3] = cpu->gprs[9];
 24			cpu->bankedRegisters[oldFIQBank][4] = cpu->gprs[10];
 25			cpu->bankedRegisters[oldFIQBank][5] = cpu->gprs[11];
 26			cpu->bankedRegisters[oldFIQBank][6] = cpu->gprs[12];
 27			cpu->gprs[8] = cpu->bankedRegisters[newFIQBank][2];
 28			cpu->gprs[9] = cpu->bankedRegisters[newFIQBank][3];
 29			cpu->gprs[10] = cpu->bankedRegisters[newFIQBank][4];
 30			cpu->gprs[11] = cpu->bankedRegisters[newFIQBank][5];
 31			cpu->gprs[12] = cpu->bankedRegisters[newFIQBank][6];
 32		}
 33		cpu->bankedRegisters[oldBank][0] = cpu->gprs[ARM_SP];
 34		cpu->bankedRegisters[oldBank][1] = cpu->gprs[ARM_LR];
 35		cpu->gprs[ARM_SP] = cpu->bankedRegisters[newBank][0];
 36		cpu->gprs[ARM_LR] = cpu->bankedRegisters[newBank][1];
 37
 38		cpu->bankedSPSRs[oldBank] = cpu->spsr.packed;
 39		cpu->spsr.packed = cpu->bankedSPSRs[newBank];
 40
 41	}
 42	cpu->privilegeMode = mode;
 43}
 44
 45static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode mode) {
 46	switch (mode) {
 47		case MODE_USER:
 48		case MODE_SYSTEM:
 49			// No banked registers
 50			return BANK_NONE;
 51		case MODE_FIQ:
 52			return BANK_FIQ;
 53		case MODE_IRQ:
 54			return BANK_IRQ;
 55		case MODE_SUPERVISOR:
 56			return BANK_SUPERVISOR;
 57		case MODE_ABORT:
 58			return BANK_ABORT;
 59		case MODE_UNDEFINED:
 60			return BANK_UNDEFINED;
 61		default:
 62			// This should be unreached
 63			return BANK_NONE;
 64	}
 65}
 66
 67void ARMInit(struct ARMCore* cpu) {
 68	cpu->master->init(cpu, cpu->master);
 69	int i;
 70	for (i = 0; i < cpu->numComponents; ++i) {
 71		cpu->components[i]->init(cpu, cpu->components[i]);
 72	}
 73}
 74
 75void ARMDeinit(struct ARMCore* cpu) {
 76	if (cpu->master->deinit) {
 77		cpu->master->deinit(cpu->master);
 78	}
 79	int i;
 80	for (i = 0; i < cpu->numComponents; ++i) {
 81		if (cpu->components[i]->deinit) {
 82			cpu->components[i]->deinit(cpu->components[i]);
 83		}
 84	}
 85}
 86
 87void ARMSetComponents(struct ARMCore* cpu, struct ARMComponent* master, int extra, struct ARMComponent** extras) {
 88	cpu->master = master;
 89	cpu->numComponents = extra;
 90	cpu->components = extras;
 91}
 92
 93
 94void ARMReset(struct ARMCore* cpu) {
 95	int i;
 96	for (i = 0; i < 16; ++i) {
 97		cpu->gprs[i] = 0;
 98	}
 99	for (i = 0; i < 6; ++i) {
100		cpu->bankedRegisters[i][0] = 0;
101		cpu->bankedRegisters[i][1] = 0;
102		cpu->bankedRegisters[i][2] = 0;
103		cpu->bankedRegisters[i][3] = 0;
104		cpu->bankedRegisters[i][4] = 0;
105		cpu->bankedRegisters[i][5] = 0;
106		cpu->bankedRegisters[i][6] = 0;
107		cpu->bankedSPSRs[i] = 0;
108	}
109
110	cpu->privilegeMode = MODE_SYSTEM;
111	cpu->cpsr.packed = MODE_SYSTEM;
112	cpu->spsr.packed = 0;
113
114	cpu->shifterOperand = 0;
115	cpu->shifterCarryOut = 0;
116
117	cpu->executionMode = MODE_THUMB;
118	_ARMSetMode(cpu, MODE_ARM);
119
120	int currentCycles = 0;
121	ARM_WRITE_PC;
122
123	cpu->cycles = 0;
124	cpu->nextEvent = 0;
125	cpu->halted = 0;
126
127	cpu->irqh.reset(cpu);
128}
129
130void ARMRaiseIRQ(struct ARMCore* cpu) {
131	if (cpu->cpsr.i) {
132		return;
133	}
134	union PSR cpsr = cpu->cpsr;
135	int instructionWidth;
136	if (cpu->executionMode == MODE_THUMB) {
137		instructionWidth = WORD_SIZE_THUMB;
138	} else {
139		instructionWidth = WORD_SIZE_ARM;
140	}
141	ARMSetPrivilegeMode(cpu, MODE_IRQ);
142	cpu->cpsr.priv = MODE_IRQ;
143	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
144	cpu->gprs[ARM_PC] = BASE_IRQ;
145	int currentCycles = 0;
146	ARM_WRITE_PC;
147	cpu->memory.setActiveRegion(cpu, cpu->gprs[ARM_PC]);
148	_ARMSetMode(cpu, MODE_ARM);
149	cpu->spsr = cpsr;
150	cpu->cpsr.i = 1;
151}
152
153void ARMRaiseSWI(struct ARMCore* cpu) {
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_SUPERVISOR);
162	cpu->cpsr.priv = MODE_SUPERVISOR;
163	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
164	cpu->gprs[ARM_PC] = BASE_SWI;
165	int currentCycles = 0;
166	ARM_WRITE_PC;
167	cpu->memory.setActiveRegion(cpu, cpu->gprs[ARM_PC]);
168	_ARMSetMode(cpu, MODE_ARM);
169	cpu->spsr = cpsr;
170	cpu->cpsr.i = 1;
171}
172
173static inline void ARMStep(struct ARMCore* cpu) {
174	uint32_t opcode = cpu->prefetch;
175	LOAD_32(cpu->prefetch, cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
176	cpu->gprs[ARM_PC] += WORD_SIZE_ARM;
177
178	unsigned condition = opcode >> 28;
179	if (condition == 0xE) {
180		ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
181		instruction(cpu, opcode);
182		return;
183	} else {
184		switch (condition) {
185		case 0x0:
186			if (!ARM_COND_EQ) {
187				cpu->cycles += ARM_PREFETCH_CYCLES;
188				return;
189			}
190			break;
191		case 0x1:
192			if (!ARM_COND_NE) {
193				cpu->cycles += ARM_PREFETCH_CYCLES;
194				return;
195			}
196			break;
197		case 0x2:
198			if (!ARM_COND_CS) {
199				cpu->cycles += ARM_PREFETCH_CYCLES;
200				return;
201			}
202			break;
203		case 0x3:
204			if (!ARM_COND_CC) {
205				cpu->cycles += ARM_PREFETCH_CYCLES;
206				return;
207			}
208			break;
209		case 0x4:
210			if (!ARM_COND_MI) {
211				cpu->cycles += ARM_PREFETCH_CYCLES;
212				return;
213			}
214			break;
215		case 0x5:
216			if (!ARM_COND_PL) {
217				cpu->cycles += ARM_PREFETCH_CYCLES;
218				return;
219			}
220			break;
221		case 0x6:
222			if (!ARM_COND_VS) {
223				cpu->cycles += ARM_PREFETCH_CYCLES;
224				return;
225			}
226			break;
227		case 0x7:
228			if (!ARM_COND_VC) {
229				cpu->cycles += ARM_PREFETCH_CYCLES;
230				return;
231			}
232			break;
233		case 0x8:
234			if (!ARM_COND_HI) {
235				cpu->cycles += ARM_PREFETCH_CYCLES;
236				return;
237			}
238			break;
239		case 0x9:
240			if (!ARM_COND_LS) {
241				cpu->cycles += ARM_PREFETCH_CYCLES;
242				return;
243			}
244			break;
245		case 0xA:
246			if (!ARM_COND_GE) {
247				cpu->cycles += ARM_PREFETCH_CYCLES;
248				return;
249			}
250			break;
251		case 0xB:
252			if (!ARM_COND_LT) {
253				cpu->cycles += ARM_PREFETCH_CYCLES;
254				return;
255			}
256			break;
257		case 0xC:
258			if (!ARM_COND_GT) {
259				cpu->cycles += ARM_PREFETCH_CYCLES;
260				return;
261			}
262			break;
263		case 0xD:
264			if (!ARM_COND_LE) {
265				cpu->cycles += ARM_PREFETCH_CYCLES;
266				return;
267			}
268			break;
269		default:
270			break;
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;
279	LOAD_16(cpu->prefetch, cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
280	cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
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	while (cpu->cycles < cpu->nextEvent) {
298		if (cpu->executionMode == MODE_THUMB) {
299			ThumbStep(cpu);
300		} else {
301			ARMStep(cpu);
302		}
303	}
304	cpu->irqh.processEvents(cpu);
305}