From 86a4e22ae1b460fab6122b607380438dbef7973b Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Fri, 18 Aug 2017 19:00:10 +0100 Subject: [PATCH] First stab at implementing GB timer control. Signed-off-by: Adrian.Conlon --- LR35902/inc/Bus.h | 52 +++++++++++++++++++++++++++++++++++++++++ LR35902/src/Bus.cpp | 8 +++++++ LR35902/src/LR35902.cpp | 2 ++ 3 files changed, 62 insertions(+) diff --git a/LR35902/inc/Bus.h b/LR35902/inc/Bus.h index 8de1f62..ca76298 100644 --- a/LR35902/inc/Bus.h +++ b/LR35902/inc/Bus.h @@ -103,6 +103,53 @@ namespace EightBit { return Memory::read(BASE + offset); } + void checkTimer(int cycles) { + if (timerEnabled()) { + m_timerCounter -= cycles; + if (m_timerCounter <= 0) { + m_timerCounter = m_timerRate; + incrementTIMA(); + } + } + } + + int timerClockTicks() { + switch (timerClock()) { + case 0b00: + return 1024; // 4.096 Khz + case 0b01: + return 16; // 262.144 Khz + case 0b10: + return 64; // 65.536 Khz + case 0b11: + return 256; // 16.384 Khz + default: + __assume(0); + } + throw std::domain_error("Invalid timer clock specification"); + } + + int timerClock() { + return readRegister(TAC) & Processor::Mask2; + } + + bool timerEnabled() { + return !timerDisabled(); + } + + bool timerDisabled() { + return (readRegister(TAC) & Processor::Bit2) == 0; + } + + void incrementTIMA() { + uint16_t updated = readRegister(TIMA) + 1; + if (updated & Processor::Bit8) { + triggerInterrupt(TimerOverflow); + updated = readRegister(TMA); + } + writeRegister(TIMA, updated & Processor::Mask8); + } + void incrementLY() { writeRegister(LY, (readRegister(LY) + 1) % TotalLineCount); } @@ -127,5 +174,10 @@ namespace EightBit { private: std::array m_boot; bool m_disableBootRom; + + int m_timerCounter; + int m_timerRate; + + void Bus_WrittenByte(const AddressEventArgs& e); }; } \ No newline at end of file diff --git a/LR35902/src/Bus.cpp b/LR35902/src/Bus.cpp index b5cd1de..6b464ef 100644 --- a/LR35902/src/Bus.cpp +++ b/LR35902/src/Bus.cpp @@ -35,4 +35,12 @@ uint8_t EightBit::Bus::peek(uint16_t address) const { if (isBootRom(effective)) return m_boot[effective]; return m_bus[effective]; +} + +void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) { + switch (e.getAddress()) { + case EightBit::Bus::BASE + TAC: + m_timerRate = timerClockTicks(); + break; + } } \ No newline at end of file diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index aca8bd7..1227873 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -354,6 +354,8 @@ int EightBit::LR35902::run(int limit) { current += step(); } + m_bus.checkTimer(current); + } while (current < limit); return current; }