bsnes/higan/gb/cpu/timing.cpp

86 lines
2.0 KiB
C++

//70224 clocks/frame
// 456 clocks/scanline
// 154 scanlines/frame
auto CPU::step(uint clocks) -> void {
for(auto n : range(clocks)) {
if(++status.clock == 0) {
cartridge.mbc3.second();
}
//4MHz / N(hz) - 1 = mask
status.div++;
if((status.div & 15) == 0) timer262144hz();
if((status.div & 63) == 0) timer65536hz();
if((status.div & 255) == 0) timer16384hz();
if((status.div & 511) == 0) timer8192hz();
if((status.div & 1023) == 0) timer4096hz();
ppu.clock -= ppu.frequency;
if(ppu.clock < 0) co_switch(ppu.thread);
apu.clock -= apu.frequency;
if(apu.clock < 0) co_switch(apu.thread);
}
if(system.sgb()) {
system._clocksExecuted += clocks;
scheduler.exit(Scheduler::Event::Step);
}
}
auto CPU::timer262144hz() -> void {
if(status.timerEnable && status.timerClock == 1) {
if(++status.tima == 0) {
status.tima = status.tma;
raise(Interrupt::Timer);
}
}
}
auto CPU::timer65536hz() -> void {
if(status.timerEnable && status.timerClock == 2) {
if(++status.tima == 0) {
status.tima = status.tma;
raise(Interrupt::Timer);
}
}
}
auto CPU::timer16384hz() -> void {
if(status.timerEnable && status.timerClock == 3) {
if(++status.tima == 0) {
status.tima = status.tma;
raise(Interrupt::Timer);
}
}
}
auto CPU::timer8192hz() -> void {
if(status.serialTransfer && status.serialClock) {
if(--status.serialBits == 0) {
status.serialTransfer = 0;
raise(Interrupt::Serial);
}
}
}
auto CPU::timer4096hz() -> void {
if(status.timerEnable && status.timerClock == 0) {
if(++status.tima == 0) {
status.tima = status.tma;
raise(Interrupt::Timer);
}
}
}
auto CPU::hblank() -> void {
if(status.dmaMode == 1 && status.dmaLength && ppu.status.ly < 144) {
for(auto n : range(16)) {
writeDMA(status.dmaTarget++, readDMA(status.dmaSource++));
}
step(8 << status.speedDouble);
status.dmaLength -= 16;
}
}