diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp index 3db9a3c7c0..8ea6714cb3 100644 --- a/libgambatte/src/cpu.cpp +++ b/libgambatte/src/cpu.cpp @@ -634,15 +634,6 @@ void CPU::process(const unsigned long cycles) { //Halt CPU and LCD display until button pressed: case 0x10: { - unsigned char followingByte; - PEEK(followingByte, PC); - PC = (PC + 1) & 0xFFFF; - - //if (followingByte != 0x00) { - //memory.di(); - //memory.blackScreen(); - //} - cycleCounter = memory.stop(cycleCounter); if (cycleCounter < memory.nextEventTime()) { @@ -1165,13 +1156,13 @@ void CPU::process(const unsigned long cycles) { //halt (4 cycles): case 0x76: - if (!memory.ime() && (memory.ff_read(0xFF0F, cycleCounter) & memory.ff_read(0xFFFF, cycleCounter) & 0x1F)) { - if (memory.isCgb()) - cycleCounter += 4; + if (memory.ff_read(0xFF0F, cycleCounter) & memory.ff_read(0xFFFF, cycleCounter) & 0x1F) { + if (memory.ime()) + PC = (PC - 1) & 0xFFFF; else skip = true; } else { - memory.halt(); + memory.halt(cycleCounter); if (cycleCounter < memory.nextEventTime()) { const unsigned long cycles = memory.nextEventTime() - cycleCounter; diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp index a5fcc148ef..46dcc6e28a 100644 --- a/libgambatte/src/memory.cpp +++ b/libgambatte/src/memory.cpp @@ -154,6 +154,9 @@ unsigned long Memory::event(unsigned long cycleCounter) { switch (intreq.minEventId()) { case UNHALT: + nontrivial_ff_write(0xFF04, 0, cycleCounter); + PC = (PC + 1) & 0xFFFF; + cycleCounter += 4; intreq.unhalt(); intreq.setEventTime(DISABLED_TIME); break; @@ -265,8 +268,12 @@ unsigned long Memory::event(unsigned long cycleCounter) { display.update(cycleCounter); break; case INTERRUPTS: + if (stopped) { + intreq.setEventTime(DISABLED_TIME); + break; + } if (halted()) { - if (gbIsCgb_) + if (gbIsCgb_ || (!gbIsCgb_ && cycleCounter <= halttime + 4)) cycleCounter += 4; intreq.unhalt(); @@ -311,7 +318,7 @@ unsigned long Memory::event(unsigned long cycleCounter) { } unsigned long Memory::stop(unsigned long cycleCounter) { - cycleCounter += 4 << isDoubleSpeed(); + cycleCounter += 4; if (ioamhram[0x14D] & isCgb()) { sound.generate_samples(cycleCounter, isDoubleSpeed()); @@ -329,17 +336,11 @@ unsigned long Memory::stop(unsigned long cycleCounter) { // otherwise, the cpu should be allowed to stay halted as long as needed // so only execute this line when switching speed intreq.halt(); - intreq.setEventTime(cycleCounter + 0x20000 + isDoubleSpeed() * 8); + intreq.setEventTime(cycleCounter + 0x20000); } else { - if ((ioamhram[0x100] & 0x30) == 0x30) { - di(); - intreq.halt(); - } - else { - intreq.halt(); - intreq.setEventTime(cycleCounter + 0x20000 + isDoubleSpeed() * 8); - } + stopped = true; + intreq.halt(); } return cycleCounter; @@ -651,6 +652,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned case 0x04: ioamhram[0x104] = 0; divLastUpdate = cycleCounter; + tima.resTac(cycleCounter, TimaInterruptRequester(intreq)); return; case 0x05: tima.setTima(data, cycleCounter, TimaInterruptRequester(intreq)); @@ -660,7 +662,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned break; case 0x07: data |= 0xF8; - tima.setTac(data, cycleCounter, TimaInterruptRequester(intreq)); + tima.setTac(data, cycleCounter, TimaInterruptRequester(intreq), gbIsCgb_); break; case 0x0F: updateIrqs(cycleCounter); diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h index ac2b5d2d17..af9758eab5 100644 --- a/libgambatte/src/memory.h +++ b/libgambatte/src/memory.h @@ -42,9 +42,11 @@ class Memory { bool cgbSwitching; bool agbMode; bool gbIsCgb_; + bool stopped; unsigned short &SP; unsigned short &PC; unsigned long basetime; + unsigned long halttime; MemoryCallback readCallback; MemoryCallback writeCallback; @@ -129,7 +131,7 @@ public: return cc < intreq.eventTime(BLIT) ? -1 : static_cast((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed()); } - void halt() { intreq.halt(); } + void halt(unsigned long cycleCounter) { halttime = cycleCounter; intreq.halt(); } void ei(unsigned long cycleCounter) { if (!ime()) { intreq.ei(cycleCounter); } } void di() { intreq.di(); } diff --git a/libgambatte/src/tima.cpp b/libgambatte/src/tima.cpp index 5272443ba2..68d49189ef 100644 --- a/libgambatte/src/tima.cpp +++ b/libgambatte/src/tima.cpp @@ -119,7 +119,7 @@ void Tima::setTma(const unsigned data, const unsigned long cycleCounter, const T tma_ = data; } -void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const TimaInterruptRequester timaIrq) { +void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const TimaInterruptRequester timaIrq, bool gbIsCgb) { if (tac_ ^ data) { unsigned long nextIrqEventTime = timaIrq.nextIrqEventTime(); @@ -142,6 +142,13 @@ void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const T if (data & 4) { lastUpdate_ = (cycleCounter >> timaClock[data & 3]) << timaClock[data & 3]; + unsigned long diff = cycleCounter - basetime_; + + if (gbIsCgb) { + if (((diff >> (timaClock[tac_ & 3] - 1)) & 1) == 1 && ((diff >> (timaClock[data & 3] - 1)) & 1) == 0) + tima_++; + } + lastUpdate_ = basetime_ + ((diff >> timaClock[data & 3]) << timaClock[data & 3]); nextIrqEventTime = lastUpdate_ + ((256u - tima_) << timaClock[data & 3]) + 3; } @@ -151,6 +158,14 @@ void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const T tac_ = data; } +void Tima::resTac(unsigned long const cycleCounter, TimaInterruptRequester timaIrq) { + basetime_ = cycleCounter; + if (tac_ & 0x04) { + setTac(tac_ & ~0x04, cycleCounter, timaIrq, false); + setTac(tac_ | 0x04, cycleCounter, timaIrq, false); + } +} + unsigned Tima::tima(unsigned long cycleCounter) { if (tac_ & 0x04) updateTima(cycleCounter); diff --git a/libgambatte/src/tima.h b/libgambatte/src/tima.h index a3c0c995bb..a66f987837 100644 --- a/libgambatte/src/tima.h +++ b/libgambatte/src/tima.h @@ -34,6 +34,7 @@ public: }; class Tima { + unsigned long basetime_; unsigned long lastUpdate_; unsigned long tmatime_; @@ -55,7 +56,8 @@ public: void setTima(unsigned tima, unsigned long cc, TimaInterruptRequester timaIrq); void setTma(unsigned tma, unsigned long cc, TimaInterruptRequester timaIrq); - void setTac(unsigned tac, unsigned long cc, TimaInterruptRequester timaIrq); + void setTac(unsigned tac, unsigned long cc, TimaInterruptRequester timaIrq, bool gbIsCgb); + void resTac(unsigned long cc, TimaInterruptRequester timaIrq); unsigned tima(unsigned long cc); void doIrqEvent(TimaInterruptRequester timaIrq); diff --git a/output/dll/libgambatte.dll b/output/dll/libgambatte.dll index 4c02731caf..6cfedd62b4 100644 Binary files a/output/dll/libgambatte.dll and b/output/dll/libgambatte.dll differ