all repos — mgba @ 1ca648715166fbca34ec4bef3ac591d9ce3a0869

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->memory = 0;
 69	cpu->board = 0;
 70}
 71
 72void ARMAssociateMemory(struct ARMCore* cpu, struct ARMMemory* memory) {
 73	cpu->memory = memory;
 74}
 75
 76void ARMAssociateBoard(struct ARMCore* cpu, struct ARMBoard* board) {
 77	cpu->board = board;
 78	board->cpu = cpu;
 79}
 80
 81void ARMReset(struct ARMCore* cpu) {
 82	int i;
 83	for (i = 0; i < 16; ++i) {
 84		cpu->gprs[i] = 0;
 85	}
 86	for (i = 0; i < 6; ++i) {
 87		cpu->bankedRegisters[i][0] = 0;
 88		cpu->bankedRegisters[i][1] = 0;
 89		cpu->bankedRegisters[i][2] = 0;
 90		cpu->bankedRegisters[i][3] = 0;
 91		cpu->bankedRegisters[i][4] = 0;
 92		cpu->bankedRegisters[i][5] = 0;
 93		cpu->bankedRegisters[i][6] = 0;
 94		cpu->bankedSPSRs[i] = 0;
 95	}
 96
 97	cpu->cpsr.packed = MODE_SYSTEM;
 98	cpu->spsr.packed = 0;
 99
100	cpu->cyclesToEvent = 0;
101
102	cpu->shifterOperand = 0;
103	cpu->shifterCarryOut = 0;
104
105	cpu->executionMode = MODE_THUMB;
106	_ARMSetMode(cpu, MODE_ARM);
107
108	cpu->board->reset(cpu->board);
109}
110
111void ARMRun(struct ARMCore* cpu) {
112	if (cpu->executionMode == MODE_THUMB) {
113		ThumbStep(cpu);
114	} else {
115		ARMStep(cpu);
116	}
117}