diff --git a/ares/component/processor/m68000/m68000.cpp b/ares/component/processor/m68000/m68000.cpp index be752caf34..cd61184ef3 100644 --- a/ares/component/processor/m68000/m68000.cpp +++ b/ares/component/processor/m68000/m68000.cpp @@ -66,7 +66,7 @@ auto M68000::exception(u32 exception, u32 vector, u32 priority) -> void { if(exception == Exception::Interrupt) { // IACK vector number acquisition (+4 cyc normal or +10 to +18 cyc autovectored) // & justify vector number (+4 cyc) - idle(16+4); // assuming autovector cycles (approximated for Megadrive) + idle(14+4); // assuming autovector cycles (approximated for Megadrive) r.i = priority; } diff --git a/ares/md/apu/bus.cpp b/ares/md/apu/bus.cpp index 27497ffb1c..783e988260 100644 --- a/ares/md/apu/bus.cpp +++ b/ares/md/apu/bus.cpp @@ -33,7 +33,9 @@ auto APU::write(n16 address, n8 data) -> void { } auto APU::readExternal(n24 address) -> n8 { + step(3); // approximate Z80 delay while(MegaDrive::bus.acquired() && !scheduler.synchronizing()) step(1); + cpu.state.stolenMcycles += 68; // approximate 68K delay; 68 Mclk ~= 9.7 68k clk MegaDrive::bus.acquire(MegaDrive::Bus::APU); n8 data = 0xff; @@ -54,7 +56,9 @@ auto APU::readExternal(n24 address) -> n8 { } auto APU::writeExternal(n24 address, n8 data) -> void { + step(3); // approximate Z80 delay while(MegaDrive::bus.acquired() && !scheduler.synchronizing()) step(1); + cpu.state.stolenMcycles += 68; // approximate 68K delay; 68 Mclk ~= 9.7 68k clk MegaDrive::bus.acquire(MegaDrive::Bus::APU); if(address >= 0x000000 && address <= 0x9fffff diff --git a/ares/md/bus/inline.hpp b/ares/md/bus/inline.hpp index d97fb31352..94ca812ee6 100644 --- a/ares/md/bus/inline.hpp +++ b/ares/md/bus/inline.hpp @@ -121,47 +121,31 @@ alwaysinline auto Bus::write(n1 upper, n1 lower, n24 address, n16 data) -> void } alwaysinline auto Bus::waitRefreshExternal() -> void { - if(state.acquired & VDPDMA) return; // refresh is synched with VDP during DMA - if(cpu.refresh.external < cpu.refresh.externalLowBound) return; - - if(cpu.refresh.externalEnd == 0) - cpu.refresh.externalEnd = min(cpu.refresh.external + cpu.refresh.externalLength, cpu.refresh.externalHighBound); - if(cpu.refresh.external < cpu.refresh.externalEnd) { - while(cpu.refresh.external < cpu.refresh.externalEnd) { - if(cpu.active()) cpu.wait(1); - if(apu.active()) apu.step(1); - if(scheduler.synchronizing()) return; - if(vdp.active()) return; - } - cpu.refresh.external -= cpu.refresh.externalEnd; - cpu.refresh.externalEnd = 0; - } + if(vdp.active() || state.acquired & VDPDMA) return; // refresh is synched with VDP during DMA while(cpu.refresh.external >= cpu.refresh.externalHighBound) { cpu.refresh.external -= cpu.refresh.externalHighBound; - cpu.refresh.externalEnd = 0; } + + if(cpu.refresh.external < cpu.refresh.externalLowBound) return; + + if(cpu.active()) cpu.wait(min(cpu.refresh.externalLength,cpu.refresh.externalHighBound-cpu.refresh.external)); + if(apu.active()) apu.step(min(cpu.refresh.externalLength,cpu.refresh.externalHighBound-cpu.refresh.external)); + + cpu.refresh.external -= cpu.refresh.externalHighBound; } alwaysinline auto Bus::waitRefreshRAM() -> void { - if(state.acquired & VDPDMA) return; // refresh is synched with VDP during DMA - if(cpu.refresh.ram < cpu.refresh.ramLowBound) return; - - if(cpu.refresh.ramEnd == 0) - cpu.refresh.ramEnd = min(cpu.refresh.ram + cpu.refresh.ramLength, cpu.refresh.ramHighBound); - if(cpu.refresh.ram < cpu.refresh.ramEnd) { - while(cpu.refresh.ram < cpu.refresh.ramEnd) { - if(cpu.active()) cpu.wait(1); - if(apu.active()) apu.step(1); - if(scheduler.synchronizing()) return; - if(vdp.active()) return; - } - cpu.refresh.ram -= cpu.refresh.ramEnd; - cpu.refresh.ramEnd = 0; - } + if(vdp.active() || state.acquired & VDPDMA) return; // refresh is synched with VDP during DMA while(cpu.refresh.ram >= cpu.refresh.ramHighBound) { cpu.refresh.ram -= cpu.refresh.ramHighBound; - cpu.refresh.ramEnd = 0; } + + if(cpu.refresh.ram < cpu.refresh.ramLowBound) return; + + if(cpu.active()) cpu.wait(min(cpu.refresh.ramLength,cpu.refresh.ramHighBound-cpu.refresh.ram)); + if(apu.active()) apu.step(min(cpu.refresh.ramLength,cpu.refresh.ramHighBound-cpu.refresh.ram)); + + cpu.refresh.ram = 0; } diff --git a/ares/md/cpu/cpu.cpp b/ares/md/cpu/cpu.cpp index e5fe5af5c2..ae5754f65a 100644 --- a/ares/md/cpu/cpu.cpp +++ b/ares/md/cpu/cpu.cpp @@ -60,6 +60,8 @@ auto CPU::main() -> void { } auto CPU::step(u32 clocks) -> void { + clocks += state.stolenMcycles/7; + state.stolenMcycles -= state.stolenMcycles/7 * 7; refresh.ram += clocks; refresh.external += clocks; Thread::step(clocks); diff --git a/ares/md/cpu/cpu.hpp b/ares/md/cpu/cpu.hpp index 1a59cc7a6f..6cd0b16801 100644 --- a/ares/md/cpu/cpu.hpp +++ b/ares/md/cpu/cpu.hpp @@ -74,14 +74,15 @@ struct CPU : M68000, Thread { static constexpr int ramLowBound = 113; static constexpr int ramHighBound = 132; static constexpr int ramLength = 3; - static constexpr int externalLowBound = 126; - static constexpr int externalHighBound = 132; + static constexpr int externalLowBound = 121; + static constexpr int externalHighBound = 128; static constexpr int externalLength = 2; } refresh; struct State { n32 interruptPending; + int stolenMcycles = 0; } state; int cyclesUntilSync = 0; diff --git a/ares/md/cpu/serialization.cpp b/ares/md/cpu/serialization.cpp index fc90841d36..9bb2dea161 100644 --- a/ares/md/cpu/serialization.cpp +++ b/ares/md/cpu/serialization.cpp @@ -10,4 +10,5 @@ auto CPU::serialize(serializer& s) -> void { s(refresh.external); s(refresh.externalEnd); s(state.interruptPending); + s(state.stolenMcycles); } diff --git a/ares/md/system/serialization.cpp b/ares/md/system/serialization.cpp index 9959c160f4..21efa43191 100644 --- a/ares/md/system/serialization.cpp +++ b/ares/md/system/serialization.cpp @@ -1,4 +1,4 @@ -static const string SerializerVersion = "v133"; +static const string SerializerVersion = "v133.1"; auto System::serialize(bool synchronize) -> serializer { if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);