mirror of https://github.com/mgba-emu/mgba.git
Start implementing instruction timing
This commit is contained in:
parent
fa64310e83
commit
ecc4775c31
|
@ -4,6 +4,8 @@
|
||||||
#include "isa-inlines.h"
|
#include "isa-inlines.h"
|
||||||
#include "isa-thumb.h"
|
#include "isa-thumb.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode);
|
static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode);
|
||||||
|
|
||||||
void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
|
void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
|
||||||
|
@ -97,7 +99,8 @@ void ARMReset(struct ARMCore* cpu) {
|
||||||
cpu->cpsr.packed = MODE_SYSTEM;
|
cpu->cpsr.packed = MODE_SYSTEM;
|
||||||
cpu->spsr.packed = 0;
|
cpu->spsr.packed = 0;
|
||||||
|
|
||||||
cpu->cyclesToEvent = 0;
|
cpu->cycles = 0;
|
||||||
|
cpu->nextEvent = INT_MAX;
|
||||||
|
|
||||||
cpu->shifterOperand = 0;
|
cpu->shifterOperand = 0;
|
||||||
cpu->shifterCarryOut = 0;
|
cpu->shifterCarryOut = 0;
|
||||||
|
|
|
@ -79,12 +79,15 @@ struct ARMMemory {
|
||||||
|
|
||||||
uint32_t* activeRegion;
|
uint32_t* activeRegion;
|
||||||
uint32_t activeMask;
|
uint32_t activeMask;
|
||||||
|
uint32_t activePrefetchCycles32;
|
||||||
|
uint32_t activePrefetchCycles16;
|
||||||
void (*setActiveRegion)(struct ARMMemory*, uint32_t address);
|
void (*setActiveRegion)(struct ARMMemory*, uint32_t address);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ARMBoard {
|
struct ARMBoard {
|
||||||
struct ARMCore* cpu;
|
struct ARMCore* cpu;
|
||||||
void (*reset)(struct ARMBoard* board);
|
void (*reset)(struct ARMBoard* board);
|
||||||
|
void (*nextEvent)(struct ARMBoard* board);
|
||||||
void (*swi16)(struct ARMBoard* board, int immediate);
|
void (*swi16)(struct ARMBoard* board, int immediate);
|
||||||
void (*swi32)(struct ARMBoard* board, int immediate);
|
void (*swi32)(struct ARMBoard* board, int immediate);
|
||||||
|
|
||||||
|
@ -96,7 +99,8 @@ struct ARMCore {
|
||||||
union PSR cpsr;
|
union PSR cpsr;
|
||||||
union PSR spsr;
|
union PSR spsr;
|
||||||
|
|
||||||
int32_t cyclesToEvent;
|
uint32_t cycles;
|
||||||
|
uint32_t nextEvent;
|
||||||
|
|
||||||
int32_t bankedRegisters[6][7];
|
int32_t bankedRegisters[6][7];
|
||||||
int32_t bankedSPSRs[6];
|
int32_t bankedSPSRs[6];
|
||||||
|
|
|
@ -106,71 +106,85 @@ void ARMStep(struct ARMCore* cpu) {
|
||||||
switch (condition) {
|
switch (condition) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
if (!ARM_COND_EQ) {
|
if (!ARM_COND_EQ) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x1:
|
case 0x1:
|
||||||
if (!ARM_COND_NE) {
|
if (!ARM_COND_NE) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x2:
|
case 0x2:
|
||||||
if (!ARM_COND_CS) {
|
if (!ARM_COND_CS) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x3:
|
case 0x3:
|
||||||
if (!ARM_COND_CC) {
|
if (!ARM_COND_CC) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x4:
|
case 0x4:
|
||||||
if (!ARM_COND_MI) {
|
if (!ARM_COND_MI) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x5:
|
case 0x5:
|
||||||
if (!ARM_COND_PL) {
|
if (!ARM_COND_PL) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x6:
|
case 0x6:
|
||||||
if (!ARM_COND_VS) {
|
if (!ARM_COND_VS) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x7:
|
case 0x7:
|
||||||
if (!ARM_COND_VC) {
|
if (!ARM_COND_VC) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x8:
|
case 0x8:
|
||||||
if (!ARM_COND_HI) {
|
if (!ARM_COND_HI) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x9:
|
case 0x9:
|
||||||
if (!ARM_COND_LS) {
|
if (!ARM_COND_LS) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xA:
|
case 0xA:
|
||||||
if (!ARM_COND_GE) {
|
if (!ARM_COND_GE) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xB:
|
case 0xB:
|
||||||
if (!ARM_COND_LT) {
|
if (!ARM_COND_LT) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xC:
|
case 0xC:
|
||||||
if (!ARM_COND_GT) {
|
if (!ARM_COND_GT) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xD:
|
case 0xD:
|
||||||
if (!ARM_COND_GE) {
|
if (!ARM_COND_GE) {
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -237,6 +251,7 @@ void ARMStep(struct ARMCore* cpu) {
|
||||||
#define DEFINE_INSTRUCTION_ARM(NAME, BODY) \
|
#define DEFINE_INSTRUCTION_ARM(NAME, BODY) \
|
||||||
static void _ARMInstruction ## NAME (struct ARMCore* cpu, uint32_t opcode) { \
|
static void _ARMInstruction ## NAME (struct ARMCore* cpu, uint32_t opcode) { \
|
||||||
BODY; \
|
BODY; \
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles32; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, S_BODY, SHIFTER, BODY, POST_BODY) \
|
#define DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, S_BODY, SHIFTER, BODY, POST_BODY) \
|
||||||
|
|
|
@ -95,6 +95,7 @@ void ThumbStep(struct ARMCore* cpu) {
|
||||||
#define DEFINE_INSTRUCTION_THUMB(NAME, BODY) \
|
#define DEFINE_INSTRUCTION_THUMB(NAME, BODY) \
|
||||||
static void _ThumbInstruction ## NAME (struct ARMCore* cpu, uint16_t opcode) { \
|
static void _ThumbInstruction ## NAME (struct ARMCore* cpu, uint16_t opcode) { \
|
||||||
BODY; \
|
BODY; \
|
||||||
|
cpu->cycles += 1 + cpu->memory->activePrefetchCycles16; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DEFINE_IMMEDIATE_5_INSTRUCTION_EX_THUMB(NAME, IMMEDIATE, BODY) \
|
#define DEFINE_IMMEDIATE_5_INSTRUCTION_EX_THUMB(NAME, IMMEDIATE, BODY) \
|
||||||
|
|
|
@ -9,6 +9,9 @@ static const char* GBA_CANNOT_MMAP = "Could not map memory";
|
||||||
|
|
||||||
static void GBASetActiveRegion(struct ARMMemory* memory, uint32_t region);
|
static void GBASetActiveRegion(struct ARMMemory* memory, uint32_t region);
|
||||||
|
|
||||||
|
static const char GBA_BASE_WAITSTATES[16] = { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4 };
|
||||||
|
static const char GBA_BASE_WAITSTATES_SEQ[16] = { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4 };
|
||||||
|
|
||||||
void GBAMemoryInit(struct GBAMemory* memory) {
|
void GBAMemoryInit(struct GBAMemory* memory) {
|
||||||
memory->d.load32 = GBALoad32;
|
memory->d.load32 = GBALoad32;
|
||||||
memory->d.load16 = GBALoad16;
|
memory->d.load16 = GBALoad16;
|
||||||
|
@ -31,6 +34,20 @@ void GBAMemoryInit(struct GBAMemory* memory) {
|
||||||
memory->p->errstr = GBA_CANNOT_MMAP;
|
memory->p->errstr = GBA_CANNOT_MMAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 16; ++i) {
|
||||||
|
memory->waitstates16[i] = GBA_BASE_WAITSTATES[i];
|
||||||
|
memory->waitstatesSeq16[i] = GBA_BASE_WAITSTATES_SEQ[i];
|
||||||
|
memory->waitstates32[i] = GBA_BASE_WAITSTATES[i] + GBA_BASE_WAITSTATES_SEQ[i] + 1;
|
||||||
|
memory->waitstatesSeq32[i] = GBA_BASE_WAITSTATES_SEQ[i] + GBA_BASE_WAITSTATES_SEQ[i] + 1;
|
||||||
|
}
|
||||||
|
for (; i < 256; ++i) {
|
||||||
|
memory->waitstates16[i] = 0;
|
||||||
|
memory->waitstatesSeq16[i] = 0;
|
||||||
|
memory->waitstates32[i] = 0;
|
||||||
|
memory->waitstatesSeq32[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
memory->d.activeRegion = 0;
|
memory->d.activeRegion = 0;
|
||||||
memory->d.activeMask = 0;
|
memory->d.activeMask = 0;
|
||||||
memory->d.setActiveRegion = GBASetActiveRegion;
|
memory->d.setActiveRegion = GBASetActiveRegion;
|
||||||
|
@ -44,6 +61,8 @@ void GBAMemoryDeinit(struct GBAMemory* memory) {
|
||||||
static void GBASetActiveRegion(struct ARMMemory* memory, uint32_t address) {
|
static void GBASetActiveRegion(struct ARMMemory* memory, uint32_t address) {
|
||||||
struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
|
struct GBAMemory* gbaMemory = (struct GBAMemory*) memory;
|
||||||
|
|
||||||
|
memory->activePrefetchCycles32 = gbaMemory->waitstates32[address >> BASE_OFFSET];
|
||||||
|
memory->activePrefetchCycles16 = gbaMemory->waitstates16[address >> BASE_OFFSET];
|
||||||
switch (address & ~OFFSET_MASK) {
|
switch (address & ~OFFSET_MASK) {
|
||||||
case BASE_BIOS:
|
case BASE_BIOS:
|
||||||
memory->activeRegion = gbaMemory->bios;
|
memory->activeRegion = gbaMemory->bios;
|
||||||
|
|
|
@ -55,7 +55,8 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
OFFSET_MASK = 0x00FFFFFF
|
OFFSET_MASK = 0x00FFFFFF,
|
||||||
|
BASE_OFFSET = 24
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBAMemory {
|
struct GBAMemory {
|
||||||
|
@ -67,6 +68,11 @@ struct GBAMemory {
|
||||||
uint32_t* iwram;
|
uint32_t* iwram;
|
||||||
uint32_t* rom;
|
uint32_t* rom;
|
||||||
uint16_t io[SIZE_IO >> 1];
|
uint16_t io[SIZE_IO >> 1];
|
||||||
|
|
||||||
|
char waitstates32[256];
|
||||||
|
char waitstates16[256];
|
||||||
|
char waitstatesSeq32[256];
|
||||||
|
char waitstatesSeq16[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
int32_t GBALoad32(struct ARMMemory* memory, uint32_t address);
|
int32_t GBALoad32(struct ARMMemory* memory, uint32_t address);
|
||||||
|
|
Loading…
Reference in New Issue