mirror of https://github.com/mgba-emu/mgba.git
ARM: You won't believe this one weird trick to make debugging easier!
This commit is contained in:
parent
257284d3e2
commit
510a539a50
|
@ -15,10 +15,10 @@ CXX_GUARD_START
|
|||
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
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ CXX_GUARD_START
|
|||
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
|
||||
|
||||
|
|
|
@ -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
|
107
src/arm/arm.c
107
src/arm/arm.c
|
@ -221,109 +221,10 @@ void ARMHalt(struct ARMCore* cpu) {
|
|||
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) {
|
||||
|
|
|
@ -917,18 +917,14 @@ DEFINE_INSTRUCTION_ARM(MSRRI,
|
|||
|
||||
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)
|
||||
};
|
||||
|
|
|
@ -454,10 +454,10 @@ DEFINE_INSTRUCTION_THUMB(BLX2,
|
|||
|
||||
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)
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue