mirror of https://github.com/mgba-emu/mgba.git
GB: Fix HALT breaking M-cycle alignment (fixes #250)
This commit is contained in:
parent
c6b25f14a3
commit
e0b07a6446
1
CHANGES
1
CHANGES
|
@ -19,6 +19,7 @@ Features:
|
||||||
Emulation fixes:
|
Emulation fixes:
|
||||||
- ARM7: Fix unsigned multiply timing
|
- ARM7: Fix unsigned multiply timing
|
||||||
- GB: Copy logo from ROM if not running the BIOS intro (fixes mgba.io/i/2378)
|
- GB: Copy logo from ROM if not running the BIOS intro (fixes mgba.io/i/2378)
|
||||||
|
- GB: Fix HALT breaking M-cycle alignment (fixes mgba.io/i/250)
|
||||||
- GB Audio: Fix channel 1/2 reseting edge cases (fixes mgba.io/i/1925)
|
- GB Audio: Fix channel 1/2 reseting edge cases (fixes mgba.io/i/1925)
|
||||||
- GB Audio: Properly apply per-model audio differences
|
- GB Audio: Properly apply per-model audio differences
|
||||||
- GB Audio: Revamp channel rendering
|
- GB Audio: Revamp channel rendering
|
||||||
|
|
77
src/gb/gb.c
77
src/gb/gb.c
|
@ -844,39 +844,67 @@ void GBUpdateIRQs(struct GB* gb) {
|
||||||
SM83RaiseIRQ(gb->cpu);
|
SM83RaiseIRQ(gb->cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _GBAdvanceCycles(struct GB* gb) {
|
||||||
|
struct SM83Core* cpu = gb->cpu;
|
||||||
|
int stateMask = (4 * (2 - gb->doubleSpeed)) - 1;
|
||||||
|
int stateOffset = ((cpu->nextEvent - cpu->cycles) & stateMask) >> !gb->doubleSpeed;
|
||||||
|
cpu->cycles = cpu->nextEvent;
|
||||||
|
cpu->executionState = (cpu->executionState + stateOffset) & 3;
|
||||||
|
}
|
||||||
|
|
||||||
void GBProcessEvents(struct SM83Core* cpu) {
|
void GBProcessEvents(struct SM83Core* cpu) {
|
||||||
struct GB* gb = (struct GB*) cpu->master;
|
struct GB* gb = (struct GB*) cpu->master;
|
||||||
do {
|
#ifndef NDEBUG
|
||||||
int32_t cycles = cpu->cycles;
|
int stateMask = (4 * (2 - gb->doubleSpeed)) - 1;
|
||||||
int32_t nextEvent;
|
int state = (mTimingGlobalTime(&gb->timing) & stateMask) >> !gb->doubleSpeed;
|
||||||
|
if (((state + 3) & 3) != (cpu->executionState & 3)) {
|
||||||
cpu->cycles = 0;
|
mLOG(GB, ERROR, "T-states and M-cycles became misaligned");
|
||||||
cpu->nextEvent = INT_MAX;
|
}
|
||||||
|
|
||||||
nextEvent = cycles;
|
|
||||||
do {
|
|
||||||
#ifdef USE_DEBUGGERS
|
|
||||||
gb->timing.globalCycles += nextEvent;
|
|
||||||
#endif
|
#endif
|
||||||
nextEvent = mTimingTick(&gb->timing, nextEvent);
|
bool wasHalted = cpu->halted;
|
||||||
} while (gb->cpuBlocked);
|
while (true) {
|
||||||
// This loop cannot early exit until the SM83 run loop properly handles mid-M-cycle-exits
|
do {
|
||||||
cpu->nextEvent = nextEvent;
|
int32_t cycles = cpu->cycles;
|
||||||
|
int32_t nextEvent;
|
||||||
|
|
||||||
if (cpu->halted) {
|
cpu->cycles = 0;
|
||||||
cpu->cycles = cpu->nextEvent;
|
cpu->nextEvent = INT_MAX;
|
||||||
if (!gb->memory.ie || !gb->memory.ime) {
|
|
||||||
|
nextEvent = cycles;
|
||||||
|
do {
|
||||||
|
#ifdef USE_DEBUGGERS
|
||||||
|
gb->timing.globalCycles += nextEvent;
|
||||||
|
#endif
|
||||||
|
nextEvent = mTimingTick(&gb->timing, nextEvent);
|
||||||
|
} while (gb->cpuBlocked);
|
||||||
|
// This loop cannot early exit until the SM83 run loop properly handles mid-M-cycle-exits
|
||||||
|
cpu->nextEvent = nextEvent;
|
||||||
|
|
||||||
|
if (cpu->halted) {
|
||||||
|
_GBAdvanceCycles(gb);
|
||||||
|
if (!gb->memory.ie || !gb->memory.ime) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gb->earlyExit) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} while (cpu->cycles >= cpu->nextEvent);
|
||||||
|
if (gb->cpuBlocked) {
|
||||||
|
_GBAdvanceCycles(gb);
|
||||||
}
|
}
|
||||||
if (gb->earlyExit) {
|
if (!wasHalted || (cpu->executionState & 3) == SM83_CORE_FETCH) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (cpu->cycles >= cpu->nextEvent);
|
int nextFetch = (SM83_CORE_FETCH - cpu->executionState) * cpu->tMultiplier;
|
||||||
gb->earlyExit = false;
|
if (nextFetch < cpu->nextEvent) {
|
||||||
if (gb->cpuBlocked) {
|
cpu->cycles += nextFetch;
|
||||||
cpu->cycles = cpu->nextEvent;
|
cpu->executionState = SM83_CORE_FETCH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_GBAdvanceCycles(gb);
|
||||||
}
|
}
|
||||||
|
gb->earlyExit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBSetInterrupts(struct SM83Core* cpu, bool enable) {
|
void GBSetInterrupts(struct SM83Core* cpu, bool enable) {
|
||||||
|
@ -928,7 +956,8 @@ static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cycle
|
||||||
void GBHalt(struct SM83Core* cpu) {
|
void GBHalt(struct SM83Core* cpu) {
|
||||||
struct GB* gb = (struct GB*) cpu->master;
|
struct GB* gb = (struct GB*) cpu->master;
|
||||||
if (!(gb->memory.ie & gb->memory.io[GB_REG_IF] & 0x1F)) {
|
if (!(gb->memory.ie & gb->memory.io[GB_REG_IF] & 0x1F)) {
|
||||||
cpu->cycles = cpu->nextEvent;
|
_GBAdvanceCycles(gb);
|
||||||
|
cpu->executionState = (cpu->executionState - 1) & 3;
|
||||||
cpu->halted = true;
|
cpu->halted = true;
|
||||||
} else if (!gb->memory.ime) {
|
} else if (!gb->memory.ime) {
|
||||||
mLOG(GB, GAME_ERROR, "HALT bug");
|
mLOG(GB, GAME_ERROR, "HALT bug");
|
||||||
|
|
Loading…
Reference in New Issue