diff --git a/ares/gba/cpu/cpu.cpp b/ares/gba/cpu/cpu.cpp index 3eed978be..38ec57b2b 100644 --- a/ares/gba/cpu/cpu.cpp +++ b/ares/gba/cpu/cpu.cpp @@ -70,6 +70,13 @@ auto CPU::step(u32 clocks) -> void { timer[1].run(); timer[2].run(); timer[3].run(); + if(context.timerLatched) { + timer[0].stepLatch(); + timer[1].stepLatch(); + timer[2].stepLatch(); + timer[3].stepLatch(); + context.timerLatched = 0; + } context.clock++; } diff --git a/ares/gba/cpu/cpu.hpp b/ares/gba/cpu/cpu.hpp index 114baac45..eae974c97 100644 --- a/ares/gba/cpu/cpu.hpp +++ b/ares/gba/cpu/cpu.hpp @@ -128,6 +128,7 @@ struct CPU : ARM7TDMI, Thread, IO { struct Timer { //timer.cpp + auto stepLatch() -> void; auto run() -> void; auto step() -> void; @@ -142,6 +143,13 @@ struct CPU : ARM7TDMI, Thread, IO { n1 cascade; n1 irq; n1 enable; + + struct Latch { + n16 reload; + n8 control; + n2 reloadFlags; + n1 controlFlag; + } latch; } timer[4]; struct Serial { @@ -229,6 +237,7 @@ struct CPU : ARM7TDMI, Thread, IO { n1 stopped; n1 booted; //set to true by the GBA BIOS n1 dmaActive; + n1 timerLatched; } context; }; diff --git a/ares/gba/cpu/io.cpp b/ares/gba/cpu/io.cpp index f6393f018..39f4dc9bf 100644 --- a/ares/gba/cpu/io.cpp +++ b/ares/gba/cpu/io.cpp @@ -301,24 +301,23 @@ auto CPU::writeIO(n32 address, n8 data) -> void { } //TM0CNT_L, TM1CNT_L, TM2CNT_L, TM3CNT_L - case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: timer().reload.byte(0) = data; return; - case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: timer().reload.byte(1) = data; return; + case 0x0400'0100: case 0x0400'0104: case 0x0400'0108: case 0x0400'010c: + timer().latch.reload.byte(0) = data; + timer().latch.reloadFlags.bit(0) = 1; + context.timerLatched = 1; + return; + case 0x0400'0101: case 0x0400'0105: case 0x0400'0109: case 0x0400'010d: + timer().latch.reload.byte(1) = data; + timer().latch.reloadFlags.bit(1) = 1; + context.timerLatched = 1; + return; //TM0CNT_H, TM1CNT_H, TM2CNT_H, TM3CNT_H - case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: { - bool enable = timer().enable; - - timer().frequency = data.bit(0,1); - timer().irq = data.bit(6); - timer().enable = data.bit(7); - - if(address != 0x0400'0102) timer().cascade = data.bit(2); - - if(!enable && timer().enable) { //0->1 transition - timer().pending = true; - } + case 0x0400'0102: case 0x0400'0106: case 0x0400'010a: case 0x0400'010e: + timer().latch.control = data; + timer().latch.controlFlag = 1; + context.timerLatched = 1; return; - } case 0x0400'0103: case 0x0400'0107: case 0x0400'010b: case 0x0400'010f: return; diff --git a/ares/gba/cpu/serialization.cpp b/ares/gba/cpu/serialization.cpp index 44d5c8ccc..4111b37d6 100644 --- a/ares/gba/cpu/serialization.cpp +++ b/ares/gba/cpu/serialization.cpp @@ -42,6 +42,10 @@ auto CPU::serialize(serializer& s) -> void { s(timer.cascade); s(timer.irq); s(timer.enable); + s(timer.latch.reload); + s(timer.latch.control); + s(timer.latch.reloadFlags); + s(timer.latch.controlFlag); } s(serial.shiftClockSelect); @@ -104,4 +108,5 @@ auto CPU::serialize(serializer& s) -> void { s(context.stopped); s(context.booted); s(context.dmaActive); + s(context.timerLatched); } diff --git a/ares/gba/cpu/timer.cpp b/ares/gba/cpu/timer.cpp index 6d3a0b817..067cecc47 100644 --- a/ares/gba/cpu/timer.cpp +++ b/ares/gba/cpu/timer.cpp @@ -1,3 +1,30 @@ +auto CPU::Timer::stepLatch() -> void { + if(latch.reloadFlags.bit(0)) { + reload.byte(0) = latch.reload.byte(0); + latch.reloadFlags.bit(0) = 0; + } + + if(latch.reloadFlags.bit(1)) { + reload.byte(1) = latch.reload.byte(1); + latch.reloadFlags.bit(1) = 0; + } + + if(latch.controlFlag) { + n1 wasEnabled = enable; + + frequency = latch.control.bit(0,1); + irq = latch.control.bit(6); + enable = latch.control.bit(7); + + if(id != 0) cascade = latch.control.bit(2); + + if(!wasEnabled && enable) { //0->1 transition + pending = true; + } + latch.controlFlag = 0; + } +} + inline auto CPU::Timer::run() -> void { if(pending) { pending = false; diff --git a/ares/gba/system/serialization.cpp b/ares/gba/system/serialization.cpp index e31a3bbfc..ce9dd53ea 100644 --- a/ares/gba/system/serialization.cpp +++ b/ares/gba/system/serialization.cpp @@ -1,4 +1,4 @@ -static const string SerializerVersion = "v131"; +static const string SerializerVersion = "v138"; auto System::serialize(bool synchronize) -> serializer { if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);