First stab at implementing GB timer control.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-08-18 19:00:10 +01:00
parent 0457dffba4
commit 86a4e22ae1
3 changed files with 62 additions and 0 deletions

View File

@ -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<uint8_t, 0x100> m_boot;
bool m_disableBootRom;
int m_timerCounter;
int m_timerRate;
void Bus_WrittenByte(const AddressEventArgs& e);
};
}

View File

@ -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;
}
}

View File

@ -354,6 +354,8 @@ int EightBit::LR35902::run(int limit) {
current += step();
}
m_bus.checkTimer(current);
} while (current < limit);
return current;
}