all repos — mgba @ 510a539a504ea914d7ea6f30ece1e15d11c02b39

mGBA Game Boy Advance Emulator

ARM: You won't believe this one weird trick to make debugging easier!
Vicki Pfau vi@endrift.com
Wed, 29 Jul 2020 17:06:29 -0700
commit

510a539a504ea914d7ea6f30ece1e15d11c02b39

parent

257284d3e209dbc67244027360c7870be030b28d

M include/mgba/internal/arm/isa-arm.hinclude/mgba/internal/arm/isa-arm.h

@@ -15,10 +15,10 @@

struct ARMCore; typedef void (*ARMInstruction)(struct ARMCore*, uint32_t opcode); -extern const ARMInstruction _armv4Table[0x1000]; -extern const ARMInstruction _armv5Table[0x1000]; -extern const ARMInstruction _armv4FTable[0x1000]; -extern const ARMInstruction _armv5FTable[0x1000]; +extern const ARMInstruction ARMv4InstructionTable[0x1000]; +extern const ARMInstruction ARMv5InstructionTable[0x1000]; +extern const ARMInstruction ARMv4FInstructionTable[0x1000]; +extern const ARMInstruction ARMv5FInstructionTable[0x1000]; CXX_GUARD_END
M include/mgba/internal/arm/isa-thumb.hinclude/mgba/internal/arm/isa-thumb.h

@@ -13,8 +13,8 @@

struct ARMCore; typedef void (*ThumbInstruction)(struct ARMCore*, uint16_t opcode); -extern const ThumbInstruction _thumbv4Table[0x400]; -extern const ThumbInstruction _thumbv5Table[0x400]; +extern const ThumbInstruction Thumbv4InstructionTable[0x400]; +extern const ThumbInstruction Thumbv5InstructionTable[0x400]; CXX_GUARD_END
A src/arm/arm-version.c

@@ -0,0 +1,124 @@

+/* Copyright (c) 2013-2020 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef VERSION +#error VERSION is undeclared +#else +// The C preprocessor is kinda bad at when it expands variables, so the indirection is needed +#define CONCAT(X, Y, Z) X ## Y ## Z +#define PREFIX_ARM(B, C) CONCAT(ARMv, B, C) +#define PREFIX_THUMB(B, C) CONCAT(Thumbv, B, C) +#define ARM(SUFFIX) PREFIX_ARM(VERSION, SUFFIX) +#define Thumb(SUFFIX) PREFIX_THUMB(VERSION, SUFFIX) +#endif + +static inline void ARM(Step)(struct ARMCore* cpu) { + uint32_t opcode = cpu->prefetch[0]; + cpu->prefetch[0] = cpu->prefetch[1]; + cpu->gprs[ARM_PC] += WORD_SIZE_ARM; + LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); + + ARMInstruction instruction; + unsigned condition = opcode >> 28; + if (condition != 0xE) { + bool conditionMet = false; + switch (condition) { + case 0x0: + conditionMet = ARM_COND_EQ; + break; + case 0x1: + conditionMet = ARM_COND_NE; + break; + case 0x2: + conditionMet = ARM_COND_CS; + break; + case 0x3: + conditionMet = ARM_COND_CC; + break; + case 0x4: + conditionMet = ARM_COND_MI; + break; + case 0x5: + conditionMet = ARM_COND_PL; + break; + case 0x6: + conditionMet = ARM_COND_VS; + break; + case 0x7: + conditionMet = ARM_COND_VC; + break; + case 0x8: + conditionMet = ARM_COND_HI; + break; + case 0x9: + conditionMet = ARM_COND_LS; + break; + case 0xA: + conditionMet = ARM_COND_GE; + break; + case 0xB: + conditionMet = ARM_COND_LT; + break; + case 0xC: + conditionMet = ARM_COND_GT; + break; + case 0xD: + conditionMet = ARM_COND_LE; + break; + default: +#if VERSION > 4 + instruction = ARM(FInstructionTable)[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; + instruction(cpu, opcode); +#endif + return; + } + if (!conditionMet) { + cpu->cycles += ARM_PREFETCH_CYCLES; + return; + } + } + instruction = ARM(InstructionTable)[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; + instruction(cpu, opcode); +} + +static inline void Thumb(Step)(struct ARMCore* cpu) { + uint32_t opcode = cpu->prefetch[0]; + cpu->prefetch[0] = cpu->prefetch[1]; + cpu->gprs[ARM_PC] += WORD_SIZE_THUMB; + LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); + ThumbInstruction instruction = Thumb(InstructionTable)[opcode >> 6]; + instruction(cpu, opcode); +} + +void ARM(Run)(struct ARMCore* cpu) { + while (cpu->cycles >= cpu->nextEvent) { + cpu->irqh.processEvents(cpu); + } + if (cpu->executionMode == MODE_THUMB) { + Thumb(Step)(cpu); + } else { + ARM(Step)(cpu); + } +} + +void ARM(RunLoop)(struct ARMCore* cpu) { + if (cpu->executionMode == MODE_THUMB) { + while (cpu->cycles < cpu->nextEvent) { + Thumb(Step)(cpu); + } + } else { + while (cpu->cycles < cpu->nextEvent) { + ARM(Step)(cpu); + } + } + cpu->irqh.processEvents(cpu); +} + +#undef ARM +#undef Thumb +#undef PREFIX_ARM +#undef PREFIX_THUMB +#undef CONCAT +#undef VERSION
M src/arm/arm.csrc/arm/arm.c

@@ -221,109 +221,10 @@ cpu->nextEvent = cpu->cycles;

cpu->halted = 1; } -#define ARM_IMPLEMENT(VERSION) \ - static inline void ARM ## VERSION ## Step(struct ARMCore* cpu) { \ - uint32_t opcode = cpu->prefetch[0]; \ - cpu->prefetch[0] = cpu->prefetch[1]; \ - cpu->gprs[ARM_PC] += WORD_SIZE_ARM; \ - LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); \ - \ - ARMInstruction instruction; \ - unsigned condition = opcode >> 28; \ - if (condition != 0xE) { \ - bool conditionMet = false; \ - switch (condition) { \ - case 0x0: \ - conditionMet = ARM_COND_EQ; \ - break; \ - case 0x1: \ - conditionMet = ARM_COND_NE; \ - break; \ - case 0x2: \ - conditionMet = ARM_COND_CS; \ - break; \ - case 0x3: \ - conditionMet = ARM_COND_CC; \ - break; \ - case 0x4: \ - conditionMet = ARM_COND_MI; \ - break; \ - case 0x5: \ - conditionMet = ARM_COND_PL; \ - break; \ - case 0x6: \ - conditionMet = ARM_COND_VS; \ - break; \ - case 0x7: \ - conditionMet = ARM_COND_VC; \ - break; \ - case 0x8: \ - conditionMet = ARM_COND_HI; \ - break; \ - case 0x9: \ - conditionMet = ARM_COND_LS; \ - break; \ - case 0xA: \ - conditionMet = ARM_COND_GE; \ - break; \ - case 0xB: \ - conditionMet = ARM_COND_LT; \ - break; \ - case 0xC: \ - conditionMet = ARM_COND_GT; \ - break; \ - case 0xD: \ - conditionMet = ARM_COND_LE; \ - break; \ - default: \ - instruction = _arm ## VERSION ## FTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; \ - instruction(cpu, opcode); \ - return; \ - } \ - if (!conditionMet) { \ - cpu->cycles += ARM_PREFETCH_CYCLES; \ - return; \ - } \ - } \ - instruction = _arm ## VERSION ## Table[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; \ - instruction(cpu, opcode); \ - } \ - \ - static inline void Thumb ## VERSION ## Step(struct ARMCore* cpu) { \ - uint32_t opcode = cpu->prefetch[0]; \ - cpu->prefetch[0] = cpu->prefetch[1]; \ - cpu->gprs[ARM_PC] += WORD_SIZE_THUMB; \ - LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); \ - ThumbInstruction instruction = _thumb ## VERSION ## Table[opcode >> 6]; \ - instruction(cpu, opcode); \ - } \ - \ - void ARM ## VERSION ## Run(struct ARMCore* cpu) { \ - while (cpu->cycles >= cpu->nextEvent) { \ - cpu->irqh.processEvents(cpu); \ - } \ - if (cpu->executionMode == MODE_THUMB) { \ - Thumb ## VERSION ## Step(cpu); \ - } else { \ - ARM ## VERSION ## Step(cpu); \ - } \ - } \ - \ - void ARM ## VERSION ## RunLoop(struct ARMCore* cpu) { \ - if (cpu->executionMode == MODE_THUMB) { \ - while (cpu->cycles < cpu->nextEvent) { \ - Thumb ## VERSION ## Step(cpu); \ - } \ - } else { \ - while (cpu->cycles < cpu->nextEvent) { \ - ARM ## VERSION ## Step(cpu); \ - } \ - } \ - cpu->irqh.processEvents(cpu); \ - } - -ARM_IMPLEMENT(v4) -ARM_IMPLEMENT(v5) +#define VERSION 4 +#include "arm/arm-version.c" +#define VERSION 5 +#include "arm/arm-version.c" void ARMRunFake(struct ARMCore* cpu, uint32_t opcode) { if (cpu->executionMode == MODE_ARM) {
M src/arm/isa-arm.csrc/arm/isa-arm.c

@@ -917,18 +917,14 @@ cpu->spsr.packed = (cpu->spsr.packed & ~mask) | (operand & mask) | 0x00000010;)

DEFINE_INSTRUCTION_ARM(SWI, cpu->irqh.swi32(cpu, opcode & 0xFFFFFF)) -const ARMInstruction _armv4Table[0x1000] = { +const ARMInstruction ARMv4InstructionTable[0x1000] = { DECLARE_ARM_EMITTER_BLOCK(_ARMInstruction, 4) }; -const ARMInstruction _armv5Table[0x1000] = { +const ARMInstruction ARMv5InstructionTable[0x1000] = { DECLARE_ARM_EMITTER_BLOCK(_ARMInstruction, 5) }; -const ARMInstruction _armv4FTable[0x1000] = { - DECLARE_ARM_F_EMITTER_BLOCK(_ARMInstruction, 4) -}; - -const ARMInstruction _armv5FTable[0x1000] = { +const ARMInstruction ARMv5FInstructionTable[0x1000] = { DECLARE_ARM_F_EMITTER_BLOCK(_ARMInstruction, 5) };
M src/arm/isa-thumb.csrc/arm/isa-thumb.c

@@ -454,10 +454,10 @@ })

DEFINE_INSTRUCTION_THUMB(SWI, cpu->irqh.swi16(cpu, opcode & 0xFF)) -const ThumbInstruction _thumbv4Table[0x400] = { +const ThumbInstruction Thumbv4InstructionTable[0x400] = { DECLARE_THUMB_EMITTER_BLOCK(_ThumbInstruction, 4) }; -const ThumbInstruction _thumbv5Table[0x400] = { +const ThumbInstruction Thumbv5InstructionTable[0x400] = { DECLARE_THUMB_EMITTER_BLOCK(_ThumbInstruction, 5) };