mirror of https://github.com/mgba-emu/mgba.git
Core: Revise clock timing (WIP)
This commit is contained in:
parent
e45519075a
commit
b2e2965273
|
@ -88,7 +88,8 @@ static inline void _ARMSetMode(struct ARMCore* cpu, enum ExecutionMode execution
|
|||
case MODE_THUMB:
|
||||
cpu->cpsr.t = 1;
|
||||
}
|
||||
cpu->nextEvent = cpu->cycles;
|
||||
cpu->nextEvent -= cpu->cycles;
|
||||
cpu->cycles = 0;
|
||||
}
|
||||
|
||||
static inline void _ARMReadCPSR(struct ARMCore* cpu) {
|
||||
|
|
|
@ -166,7 +166,7 @@ void ARMRaiseIRQ(struct ARMCore* cpu) {
|
|||
_ARMSetMode(cpu, MODE_ARM);
|
||||
cpu->spsr = cpsr;
|
||||
cpu->cpsr.i = 1;
|
||||
cpu->cycles += currentCycles;
|
||||
cpu->cycles -= currentCycles;
|
||||
}
|
||||
|
||||
void ARMRaiseSWI(struct ARMCore* cpu) {
|
||||
|
@ -186,7 +186,7 @@ void ARMRaiseSWI(struct ARMCore* cpu) {
|
|||
_ARMSetMode(cpu, MODE_ARM);
|
||||
cpu->spsr = cpsr;
|
||||
cpu->cpsr.i = 1;
|
||||
cpu->cycles += currentCycles;
|
||||
cpu->cycles -= currentCycles;
|
||||
}
|
||||
|
||||
void ARMRaiseUndefined(struct ARMCore* cpu) {
|
||||
|
@ -206,7 +206,7 @@ void ARMRaiseUndefined(struct ARMCore* cpu) {
|
|||
_ARMSetMode(cpu, MODE_ARM);
|
||||
cpu->spsr = cpsr;
|
||||
cpu->cpsr.i = 1;
|
||||
cpu->cycles += currentCycles;
|
||||
cpu->cycles -= currentCycles;
|
||||
}
|
||||
|
||||
static inline void ARMStep(struct ARMCore* cpu) {
|
||||
|
@ -265,7 +265,7 @@ static inline void ARMStep(struct ARMCore* cpu) {
|
|||
break;
|
||||
}
|
||||
if (!conditionMet) {
|
||||
cpu->cycles += ARM_PREFETCH_CYCLES;
|
||||
cpu->cycles -= ARM_PREFETCH_CYCLES;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -288,18 +288,18 @@ void ARMRun(struct ARMCore* cpu) {
|
|||
} else {
|
||||
ARMStep(cpu);
|
||||
}
|
||||
if (cpu->cycles >= cpu->nextEvent) {
|
||||
if (cpu->cycles <= 0) {
|
||||
cpu->irqh.processEvents(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
void ARMRunLoop(struct ARMCore* cpu) {
|
||||
if (cpu->executionMode == MODE_THUMB) {
|
||||
while (cpu->cycles < cpu->nextEvent) {
|
||||
while (cpu->cycles > 0) {
|
||||
ThumbStep(cpu);
|
||||
}
|
||||
} else {
|
||||
while (cpu->cycles < cpu->nextEvent) {
|
||||
while (cpu->cycles > 0) {
|
||||
ARMStep(cpu);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,7 +139,9 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) {
|
|||
static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
|
||||
struct ARMDebugger* debugger = (struct ARMDebugger*) platform;
|
||||
struct ARMCore* cpu = debugger->cpu;
|
||||
cpu->nextEvent = cpu->cycles;
|
||||
cpu->nextEvent -= cpu->cycles;
|
||||
cpu->cycles = 0;
|
||||
|
||||
if (reason == DEBUGGER_ENTER_BREAKPOINT) {
|
||||
struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu));
|
||||
if (breakpoint && breakpoint->isSw) {
|
||||
|
|
|
@ -288,7 +288,7 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) {
|
|||
static void _ARMInstruction ## NAME (struct ARMCore* cpu, uint32_t opcode) { \
|
||||
int currentCycles = ARM_PREFETCH_CYCLES; \
|
||||
BODY; \
|
||||
cpu->cycles += currentCycles; \
|
||||
cpu->cycles -= currentCycles; \
|
||||
}
|
||||
|
||||
#define DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, S_BODY, SHIFTER, BODY) \
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
static void _ThumbInstruction ## NAME (struct ARMCore* cpu, uint16_t opcode) { \
|
||||
int currentCycles = THUMB_PREFETCH_CYCLES; \
|
||||
BODY; \
|
||||
cpu->cycles += currentCycles; \
|
||||
cpu->cycles -= currentCycles; \
|
||||
}
|
||||
|
||||
#define DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(NAME, BODY) \
|
||||
|
|
|
@ -23,9 +23,10 @@ void mTimingClear(struct mTiming* timing) {
|
|||
}
|
||||
|
||||
void mTimingSchedule(struct mTiming* timing, struct mTimingEvent* event, int32_t when) {
|
||||
int32_t nextEvent = when + *timing->relativeCycles;
|
||||
int32_t nextEvent = when + *timing->nextEvent - *timing->relativeCycles;
|
||||
event->when = nextEvent + timing->masterCycles;
|
||||
if (nextEvent < *timing->nextEvent) {
|
||||
if (when < *timing->relativeCycles) {
|
||||
*timing->relativeCycles = when;
|
||||
*timing->nextEvent = nextEvent;
|
||||
}
|
||||
struct mTimingEvent** previous = &timing->root;
|
||||
|
@ -91,7 +92,7 @@ int32_t mTimingTick(struct mTiming* timing, int32_t cycles) {
|
|||
}
|
||||
|
||||
int32_t mTimingCurrentTime(const struct mTiming* timing) {
|
||||
return timing->masterCycles + *timing->relativeCycles;
|
||||
return timing->masterCycles + *timing->nextEvent - *timing->relativeCycles;
|
||||
}
|
||||
|
||||
int32_t mTimingNextEvent(struct mTiming* timing) {
|
||||
|
@ -99,9 +100,9 @@ int32_t mTimingNextEvent(struct mTiming* timing) {
|
|||
if (!next) {
|
||||
return INT_MAX;
|
||||
}
|
||||
return next->when - timing->masterCycles - *timing->relativeCycles;
|
||||
return next->when - timing->masterCycles - *timing->nextEvent + *timing->relativeCycles;
|
||||
}
|
||||
|
||||
int32_t mTimingUntil(const struct mTiming* timing, const struct mTimingEvent* event) {
|
||||
return event->when - timing->masterCycles - *timing->relativeCycles;
|
||||
return event->when - timing->masterCycles - *timing->nextEvent + *timing->relativeCycles;
|
||||
}
|
||||
|
|
11
src/gb/gb.c
11
src/gb/gb.c
|
@ -639,10 +639,10 @@ void GBUpdateIRQs(struct GB* gb) {
|
|||
void GBProcessEvents(struct LR35902Core* cpu) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
do {
|
||||
int32_t cycles = cpu->cycles;
|
||||
int32_t cycles = cpu->nextEvent - cpu->cycles;
|
||||
int32_t nextEvent;
|
||||
|
||||
cpu->cycles = 0;
|
||||
cpu->cycles = INT_MAX;
|
||||
cpu->nextEvent = INT_MAX;
|
||||
|
||||
nextEvent = cycles;
|
||||
|
@ -650,9 +650,10 @@ void GBProcessEvents(struct LR35902Core* cpu) {
|
|||
nextEvent = mTimingTick(&gb->timing, nextEvent);
|
||||
} while (gb->cpuBlocked);
|
||||
cpu->nextEvent = nextEvent;
|
||||
cpu->cycles = nextEvent;
|
||||
|
||||
if (cpu->halted) {
|
||||
cpu->cycles = cpu->nextEvent;
|
||||
cpu->cycles = 0;
|
||||
if (!gb->memory.ie || !gb->memory.ime) {
|
||||
break;
|
||||
}
|
||||
|
@ -660,7 +661,7 @@ void GBProcessEvents(struct LR35902Core* cpu) {
|
|||
if (gb->earlyExit) {
|
||||
break;
|
||||
}
|
||||
} while (cpu->cycles >= cpu->nextEvent);
|
||||
} while (cpu->cycles <= 0);
|
||||
gb->earlyExit = false;
|
||||
}
|
||||
|
||||
|
@ -713,7 +714,7 @@ static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cycle
|
|||
void GBHalt(struct LR35902Core* cpu) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
if (!(gb->memory.ie & gb->memory.io[REG_IF])) {
|
||||
cpu->cycles = cpu->nextEvent;
|
||||
cpu->cycles = 0;
|
||||
cpu->halted = true;
|
||||
} else if (gb->model < GB_MODEL_CGB) {
|
||||
mLOG(GB, STUB, "Unimplemented HALT bug");
|
||||
|
|
|
@ -476,8 +476,9 @@ void GBMemoryDMA(struct GB* gb, uint16_t base) {
|
|||
}
|
||||
mTimingDeschedule(&gb->timing, &gb->memory.dmaEvent);
|
||||
mTimingSchedule(&gb->timing, &gb->memory.dmaEvent, 8);
|
||||
if (gb->cpu->cycles + 8 < gb->cpu->nextEvent) {
|
||||
gb->cpu->nextEvent = gb->cpu->cycles + 8;
|
||||
if (gb->cpu->cycles < 8) {
|
||||
gb->cpu->nextEvent += 8 - gb->cpu->cycles;
|
||||
gb->cpu->cycles = 8;
|
||||
}
|
||||
gb->memory.dmaSource = base;
|
||||
gb->memory.dmaDest = 0;
|
||||
|
|
|
@ -43,7 +43,8 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
|
|||
STORE_16LE(gb->cpu->sp, 0, &state->cpu.sp);
|
||||
STORE_16LE(gb->cpu->pc, 0, &state->cpu.pc);
|
||||
|
||||
STORE_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
|
||||
int32_t cycles = gb->cpu->nextEvent - gb->cpu->cycles;
|
||||
STORE_32LE(cycles, 0, &state->cpu.cycles);
|
||||
STORE_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
|
||||
|
||||
STORE_16LE(gb->cpu->index, 0, &state->cpu.index);
|
||||
|
@ -163,8 +164,10 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
|||
gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);
|
||||
gb->audio.timingFactor = gb->doubleSpeed + 1;
|
||||
|
||||
LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles);
|
||||
int32_t cycles;
|
||||
LOAD_32LE(cycles, 0, &state->cpu.cycles);
|
||||
LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent);
|
||||
gb->cpu->cycles = gb->cpu->nextEvent - cycles;
|
||||
gb->timing.root = NULL;
|
||||
|
||||
uint32_t when;
|
||||
|
|
|
@ -251,23 +251,20 @@ static void GBAProcessEvents(struct ARMCore* cpu) {
|
|||
}
|
||||
|
||||
int32_t nextEvent = cpu->nextEvent;
|
||||
while (cpu->cycles >= nextEvent) {
|
||||
while (cpu->cycles <= 0) {
|
||||
int32_t cycles = cpu->nextEvent - cpu->cycles;
|
||||
cpu->nextEvent = INT_MAX;
|
||||
nextEvent = 0;
|
||||
cpu->cycles = INT_MAX;
|
||||
nextEvent = cycles;
|
||||
do {
|
||||
int32_t cycles = cpu->cycles;
|
||||
cpu->cycles = 0;
|
||||
#ifndef NDEBUG
|
||||
if (cycles < 0) {
|
||||
mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles);
|
||||
}
|
||||
#endif
|
||||
nextEvent = mTimingTick(&gba->timing, nextEvent + cycles);
|
||||
nextEvent = mTimingTick(&gba->timing, nextEvent);
|
||||
} while (gba->cpuBlocked);
|
||||
|
||||
cpu->nextEvent = nextEvent;
|
||||
cpu->cycles = nextEvent;
|
||||
|
||||
if (cpu->halted) {
|
||||
cpu->cycles = nextEvent;
|
||||
cpu->cycles = 0;
|
||||
if (!gba->memory.io[REG_IME >> 1] || !gba->memory.io[REG_IE >> 1]) {
|
||||
break;
|
||||
}
|
||||
|
@ -499,12 +496,13 @@ void GBATestIRQ(struct ARMCore* cpu) {
|
|||
struct GBA* gba = (struct GBA*) cpu->master;
|
||||
if (gba->memory.io[REG_IME >> 1] && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) {
|
||||
gba->springIRQ = gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1];
|
||||
gba->cpu->nextEvent = gba->cpu->cycles;
|
||||
gba->cpu->nextEvent -= gba->cpu->cycles;
|
||||
gba->cpu->cycles = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GBAHalt(struct GBA* gba) {
|
||||
gba->cpu->nextEvent = gba->cpu->cycles;
|
||||
gba->cpu->cycles = 0;
|
||||
gba->cpu->halted = 1;
|
||||
}
|
||||
|
||||
|
@ -516,7 +514,7 @@ void GBAStop(struct GBA* gba) {
|
|||
callbacks->sleep(callbacks->context);
|
||||
}
|
||||
}
|
||||
gba->cpu->nextEvent = gba->cpu->cycles;
|
||||
gba->cpu->cycles = 0;
|
||||
}
|
||||
|
||||
void GBADebug(struct GBA* gba, uint16_t flags) {
|
||||
|
|
|
@ -1613,7 +1613,7 @@ int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) {
|
|||
memory->lastPrefetchedPc = cpu->gprs[ARM_PC] + WORD_SIZE_THUMB * (loads + previousLoads - 1);
|
||||
|
||||
// The next |loads|S waitstates disappear entirely, so long as they're all in a row
|
||||
cpu->cycles -= (s - 1) * loads;
|
||||
cpu->cycles += (s - 1) * loads;
|
||||
return wait;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,9 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
|
|||
}
|
||||
STORE_32(gba->cpu->cpsr.packed, 0, &state->cpu.cpsr.packed);
|
||||
STORE_32(gba->cpu->spsr.packed, 0, &state->cpu.spsr.packed);
|
||||
STORE_32(gba->cpu->cycles, 0, &state->cpu.cycles);
|
||||
|
||||
int32_t cycles = gba->cpu->nextEvent - gba->cpu->cycles;
|
||||
STORE_32(cycles, 0, &state->cpu.cycles);
|
||||
STORE_32(gba->cpu->nextEvent, 0, &state->cpu.nextEvent);
|
||||
for (i = 0; i < 6; ++i) {
|
||||
int j;
|
||||
|
@ -136,8 +138,12 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
|||
}
|
||||
LOAD_32(gba->cpu->cpsr.packed, 0, &state->cpu.cpsr.packed);
|
||||
LOAD_32(gba->cpu->spsr.packed, 0, &state->cpu.spsr.packed);
|
||||
LOAD_32(gba->cpu->cycles, 0, &state->cpu.cycles);
|
||||
|
||||
int32_t cycles;
|
||||
LOAD_32(cycles, 0, &state->cpu.cycles);
|
||||
LOAD_32(gba->cpu->nextEvent, 0, &state->cpu.nextEvent);
|
||||
gba->cpu->cycles = gba->cpu->nextEvent - cycles;
|
||||
|
||||
for (i = 0; i < 6; ++i) {
|
||||
int j;
|
||||
for (j = 0; j < 7; ++j) {
|
||||
|
|
|
@ -123,7 +123,8 @@ static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebug
|
|||
UNUSED(info);
|
||||
struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform;
|
||||
struct LR35902Core* cpu = debugger->cpu;
|
||||
cpu->nextEvent = cpu->cycles;
|
||||
cpu->nextEvent -= cpu->cycles;
|
||||
cpu->cycles = 0;
|
||||
|
||||
if (debugger->d.p->entered) {
|
||||
debugger->d.p->entered(debugger->d.p, reason, info);
|
||||
|
|
|
@ -102,7 +102,7 @@ static void _LR35902InstructionIRQ(struct LR35902Core* cpu) {
|
|||
}
|
||||
|
||||
static void _LR35902Step(struct LR35902Core* cpu) {
|
||||
++cpu->cycles;
|
||||
--cpu->cycles;
|
||||
enum LR35902ExecutionState state = cpu->executionState;
|
||||
cpu->executionState = LR35902_CORE_IDLE_0;
|
||||
switch (state) {
|
||||
|
@ -137,44 +137,44 @@ static void _LR35902Step(struct LR35902Core* cpu) {
|
|||
}
|
||||
|
||||
void LR35902Tick(struct LR35902Core* cpu) {
|
||||
while (cpu->cycles >= cpu->nextEvent) {
|
||||
while (cpu->cycles <= 0) {
|
||||
cpu->irqh.processEvents(cpu);
|
||||
}
|
||||
_LR35902Step(cpu);
|
||||
if (cpu->cycles + 2 >= cpu->nextEvent) {
|
||||
int32_t diff = cpu->nextEvent - cpu->cycles;
|
||||
cpu->cycles = cpu->nextEvent;
|
||||
if (cpu->cycles <= 2) {
|
||||
int32_t diff = cpu->cycles;
|
||||
cpu->cycles = 0;
|
||||
cpu->executionState += diff;
|
||||
cpu->irqh.processEvents(cpu);
|
||||
cpu->cycles += LR35902_CORE_EXECUTE - cpu->executionState;
|
||||
cpu->cycles -= LR35902_CORE_EXECUTE - cpu->executionState;
|
||||
} else {
|
||||
cpu->cycles += 2;
|
||||
cpu->cycles -= 2;
|
||||
}
|
||||
cpu->executionState = LR35902_CORE_FETCH;
|
||||
cpu->instruction(cpu);
|
||||
++cpu->cycles;
|
||||
--cpu->cycles;
|
||||
}
|
||||
|
||||
void LR35902Run(struct LR35902Core* cpu) {
|
||||
bool running = true;
|
||||
while (running || cpu->executionState != LR35902_CORE_FETCH) {
|
||||
if (cpu->cycles >= cpu->nextEvent) {
|
||||
if (cpu->cycles <= 0) {
|
||||
cpu->irqh.processEvents(cpu);
|
||||
break;
|
||||
}
|
||||
_LR35902Step(cpu);
|
||||
if (cpu->cycles + 2 >= cpu->nextEvent) {
|
||||
int32_t diff = cpu->nextEvent - cpu->cycles;
|
||||
cpu->cycles = cpu->nextEvent;
|
||||
if (cpu->cycles <= 2) {
|
||||
int32_t diff = cpu->cycles;
|
||||
cpu->cycles = 0;
|
||||
cpu->executionState += diff;
|
||||
cpu->irqh.processEvents(cpu);
|
||||
cpu->cycles += LR35902_CORE_EXECUTE - cpu->executionState;
|
||||
cpu->cycles -= LR35902_CORE_EXECUTE - cpu->executionState;
|
||||
running = false;
|
||||
} else {
|
||||
cpu->cycles += 2;
|
||||
cpu->cycles -= 2;
|
||||
}
|
||||
cpu->executionState = LR35902_CORE_FETCH;
|
||||
cpu->instruction(cpu);
|
||||
++cpu->cycles;
|
||||
--cpu->cycles;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue