all repos — mgba @ ff03bcf0f0a1aa39a15619102c95eb8bd7255a93

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
  7#include <limits.h>
  8
  9static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode);
 10
 11void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
 12	if (mode == cpu->privilegeMode) {
 13		// Not switching modes after all
 14		return;
 15	}
 16
 17	enum RegisterBank newBank = _ARMSelectBank(mode);
 18	enum RegisterBank oldBank = _ARMSelectBank(cpu->privilegeMode);
 19	if (newBank != oldBank) {
 20		// Switch banked registers
 21		if (mode == MODE_FIQ || cpu->privilegeMode == MODE_FIQ) {
 22			int oldFIQBank = oldBank == BANK_FIQ;
 23			int newFIQBank = newBank == BANK_FIQ;
 24			cpu->bankedRegisters[oldFIQBank][2] = cpu->gprs[8];
 25			cpu->bankedRegisters[oldFIQBank][3] = cpu->gprs[9];
 26			cpu->bankedRegisters[oldFIQBank][4] = cpu->gprs[10];
 27			cpu->bankedRegisters[oldFIQBank][5] = cpu->gprs[11];
 28			cpu->bankedRegisters[oldFIQBank][6] = cpu->gprs[12];
 29			cpu->gprs[8] = cpu->bankedRegisters[newFIQBank][2];
 30			cpu->gprs[9] = cpu->bankedRegisters[newFIQBank][3];
 31			cpu->gprs[10] = cpu->bankedRegisters[newFIQBank][4];
 32			cpu->gprs[11] = cpu->bankedRegisters[newFIQBank][5];
 33			cpu->gprs[12] = cpu->bankedRegisters[newFIQBank][6];
 34		}
 35		cpu->bankedRegisters[oldBank][0] = cpu->gprs[ARM_SP];
 36		cpu->bankedRegisters[oldBank][1] = cpu->gprs[ARM_LR];
 37		cpu->gprs[ARM_SP] = cpu->bankedRegisters[newBank][0];
 38		cpu->gprs[ARM_LR] = cpu->bankedRegisters[newBank][1];
 39
 40		cpu->bankedSPSRs[oldBank] = cpu->spsr.packed;
 41		cpu->spsr.packed = cpu->bankedSPSRs[newBank];
 42
 43	}
 44	cpu->privilegeMode = mode;
 45}
 46
 47static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode mode) {
 48	switch (mode) {
 49		case MODE_USER:
 50		case MODE_SYSTEM:
 51			// No banked registers
 52			return BANK_NONE;
 53		case MODE_FIQ:
 54			return BANK_FIQ;
 55		case MODE_IRQ:
 56			return BANK_IRQ;
 57		case MODE_SUPERVISOR:
 58			return BANK_SUPERVISOR;
 59		case MODE_ABORT:
 60			return BANK_ABORT;
 61		case MODE_UNDEFINED:
 62			return BANK_UNDEFINED;
 63		default:
 64			// This should be unreached
 65			return BANK_NONE;
 66	}
 67}
 68
 69void ARMInit(struct ARMCore* cpu) {
 70	cpu->memory = 0;
 71	cpu->board = 0;
 72}
 73
 74void ARMAssociateMemory(struct ARMCore* cpu, struct ARMMemory* memory) {
 75	cpu->memory = memory;
 76}
 77
 78void ARMAssociateBoard(struct ARMCore* cpu, struct ARMBoard* board) {
 79	cpu->board = board;
 80	board->cpu = cpu;
 81}
 82
 83void ARMReset(struct ARMCore* cpu) {
 84	int i;
 85	for (i = 0; i < 16; ++i) {
 86		cpu->gprs[i] = 0;
 87	}
 88	for (i = 0; i < 6; ++i) {
 89		cpu->bankedRegisters[i][0] = 0;
 90		cpu->bankedRegisters[i][1] = 0;
 91		cpu->bankedRegisters[i][2] = 0;
 92		cpu->bankedRegisters[i][3] = 0;
 93		cpu->bankedRegisters[i][4] = 0;
 94		cpu->bankedRegisters[i][5] = 0;
 95		cpu->bankedRegisters[i][6] = 0;
 96		cpu->bankedSPSRs[i] = 0;
 97	}
 98
 99	cpu->privilegeMode = MODE_SYSTEM;
100	cpu->cpsr.packed = MODE_SYSTEM;
101	cpu->spsr.packed = 0;
102
103	cpu->cycles = 0;
104	cpu->nextEvent = 0;
105
106	cpu->shifterOperand = 0;
107	cpu->shifterCarryOut = 0;
108
109	cpu->executionMode = MODE_THUMB;
110	_ARMSetMode(cpu, MODE_ARM);
111
112	cpu->board->reset(cpu->board);
113}
114
115void ARMRaiseIRQ(struct ARMCore* cpu) {
116	if (cpu->cpsr.i) {
117		return;
118	}
119	union PSR cpsr = cpu->cpsr;
120	int instructionWidth;
121	if (cpu->executionMode == MODE_THUMB) {
122		instructionWidth = WORD_SIZE_THUMB;
123	} else {
124		instructionWidth = WORD_SIZE_ARM;
125	}
126	ARMSetPrivilegeMode(cpu, MODE_IRQ);
127	cpu->cpsr.priv = MODE_IRQ;
128	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
129	cpu->gprs[ARM_PC] = BASE_IRQ + WORD_SIZE_ARM;
130	cpu->memory->setActiveRegion(cpu->memory, cpu->gprs[ARM_PC]);
131	_ARMSetMode(cpu, MODE_ARM);
132	cpu->spsr = cpsr;
133	cpu->cpsr.i = 1;
134}
135
136void ARMRun(struct ARMCore* cpu) {
137	if (cpu->executionMode == MODE_THUMB) {
138		ThumbStep(cpu);
139	} else {
140		ARMStep(cpu);
141	}
142	if (cpu->cycles >= cpu->nextEvent) {
143		cpu->board->processEvents(cpu->board);
144	}
145}