all repos — mgba @ c62d913e233e7ea3bb23a3f52fcb7b481f2faed5

mGBA Game Boy Advance Emulator

src/arm/arm-version.c (view raw)

  1/* Copyright (c) 2013-2020 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#ifndef VERSION
  7#error VERSION is undeclared
  8#else
  9// The C preprocessor is kinda bad at when it expands variables, so the indirection is needed
 10#define CONCAT(X, Y, Z) X ## Y ## Z
 11#define PREFIX_ARM(B, C) CONCAT(ARMv, B, C)
 12#define PREFIX_THUMB(B, C) CONCAT(Thumbv, B, C)
 13#define ARM(SUFFIX) PREFIX_ARM(VERSION, SUFFIX)
 14#define Thumb(SUFFIX) PREFIX_THUMB(VERSION, SUFFIX)
 15#endif
 16
 17static inline void ARM(Step)(struct ARMCore* cpu) {
 18	uint32_t opcode = cpu->prefetch[0];
 19	cpu->prefetch[0] = cpu->prefetch[1];
 20	cpu->gprs[ARM_PC] += WORD_SIZE_ARM;
 21	LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
 22
 23	ARMInstruction instruction;
 24	unsigned condition = opcode >> 28;
 25	if (condition != 0xE) {
 26		bool conditionMet = false;
 27		switch (condition) {
 28		case 0x0:
 29			conditionMet = ARM_COND_EQ;
 30			break;
 31		case 0x1:
 32			conditionMet = ARM_COND_NE;
 33			break;
 34		case 0x2:
 35			conditionMet = ARM_COND_CS;
 36			break;
 37		case 0x3:
 38			conditionMet = ARM_COND_CC;
 39			break;
 40		case 0x4:
 41			conditionMet = ARM_COND_MI;
 42			break;
 43		case 0x5:
 44			conditionMet = ARM_COND_PL;
 45			break;
 46		case 0x6:
 47			conditionMet = ARM_COND_VS;
 48			break;
 49		case 0x7:
 50			conditionMet = ARM_COND_VC;
 51			break;
 52		case 0x8:
 53			conditionMet = ARM_COND_HI;
 54			break;
 55		case 0x9:
 56			conditionMet = ARM_COND_LS;
 57			break;
 58		case 0xA:
 59			conditionMet = ARM_COND_GE;
 60			break;
 61		case 0xB:
 62			conditionMet = ARM_COND_LT;
 63			break;
 64		case 0xC:
 65			conditionMet = ARM_COND_GT;
 66			break;
 67		case 0xD:
 68			conditionMet = ARM_COND_LE;
 69			break;
 70		default:
 71#if VERSION > 4
 72			instruction = ARM(FInstructionTable)[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
 73			instruction(cpu, opcode);
 74#endif
 75			return;
 76		}
 77		if (!conditionMet) {
 78			cpu->cycles += ARM_PREFETCH_CYCLES;
 79			return;
 80		}
 81	}
 82	instruction = ARM(InstructionTable)[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
 83	instruction(cpu, opcode);
 84}
 85
 86static inline void Thumb(Step)(struct ARMCore* cpu) {
 87	uint32_t opcode = cpu->prefetch[0];
 88	cpu->prefetch[0] = cpu->prefetch[1];
 89	cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
 90	LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion);
 91	ThumbInstruction instruction = Thumb(InstructionTable)[opcode >> 6];
 92	instruction(cpu, opcode);
 93}
 94
 95void ARM(Run)(struct ARMCore* cpu) {
 96	while (cpu->cycles >= cpu->nextEvent) {
 97		cpu->irqh.processEvents(cpu);
 98	}
 99	if (cpu->executionMode == MODE_THUMB) {
100		Thumb(Step)(cpu);
101	} else {
102		ARM(Step)(cpu);
103	}
104}
105
106void ARM(RunLoop)(struct ARMCore* cpu) {
107	if (cpu->executionMode == MODE_THUMB) {
108		while (cpu->cycles < cpu->nextEvent) {
109			Thumb(Step)(cpu);
110		}
111	} else {
112		while (cpu->cycles < cpu->nextEvent) {
113			ARM(Step)(cpu);
114		}
115	}
116	cpu->irqh.processEvents(cpu);
117}
118
119#undef ARM
120#undef Thumb
121#undef PREFIX_ARM
122#undef PREFIX_THUMB
123#undef CONCAT
124#undef VERSION