ARM: You won't believe this one weird trick to make debugging easier!

This commit is contained in:
Vicki Pfau 2020-07-29 17:06:29 -07:00
parent 257284d3e2
commit 510a539a50
6 changed files with 139 additions and 118 deletions

View File

@ -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

View File

@ -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

124
src/arm/arm-version.c Normal file
View File

@ -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

View File

@ -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) {

View File

@ -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)
};

View File

@ -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)
};